/**
 **	$Header: /roq/libsdsc/bin.c 1     11/02/99 4:39p Zaphod $
 **	Copyright (c) 1989-1995  San Diego Supercomputer Center (SDSC)
 **		a division of General Atomics, San Diego, California, USA
 **
 **	Users and possessors of this source code are hereby granted a
 **	nonexclusive, royalty-free copyright and design patent license to
 **	use this code in individual software.  License is not granted for
 **	commercial resale, in whole or in part, without prior written
 **	permission from SDSC.  This source is provided "AS IS" without express
 **	or implied warranty of any kind.
 **
 **	For further information contact:
 **		E-Mail:		info@sds.sdsc.edu
 **
 **		Surface Mail:	Information Center
 **				San Diego Supercomputer Center
 **				P.O. Box 85608
 **				San Diego, CA  92138-5608
 **				(619) 534-5000
 **/

#define HEADER	"    $Header: /roq/libsdsc/bin.c 1     11/02/99 4:39p Zaphod $"

/**
 **  FILE
 **	bin.c		-  Binary I/O Functions
 **
 **  PROJECT
 **	libsdsc		-  SDSC standard function library
 **
 **  DESCRIPTION
 **	This file contains source for the portable binary I/O function set.
 **	These functions allow binary files to be read and written regardless
 **	of the machine type and its word size and structure field padding.
 **
 **  ASSUMPTIONS!!!
 **	It is assumed that a variable of type 'char' is exactly 8-bits long,
 **	and no longer!
 **
 **	The size of variables, and the resolution (amount of storage actually
 **	used) are both assumed to be multiplies of 1 byte (8-bits).
 **
 **	It is assumed that the host represents integers in 2's compliment form.
 **
 **	See the discussion of the 'binFloatFormatInfo' structure for further
 **	assumptions regarding floating point.
 **
 **  PUBLIC CONTENTS
 **			d =defined constant
 **			f =function
 **			m =defined macro
 **			t =typedef/struct/union
 **			v =variable
 **			? =other
 **
 **	BinErrNo	v  error number
 **	BinNErr		v  number of error messages
 **	BinErrList	v  error messages
 **
 **	BinQMachine	f  Query machine information
 **	BinPError	f  Print error message
 **	BinQError	f  Query error message
 **	BinErrorHandler	f  nominate an error condition handler func
 **
 **	BinByteOrder	f  Select the byte order of the file
 **	BinQByteOrder	f  Query the byte order of the file
 **	BinFloatFormat	f  Select the floating point format of the file
 **	BinQFloatFormat	f  Query the floating point format of the file
 **
 **	BinRead		f  Read binary file using unbuffered I/O
 **	BinFRead	f  Read binary file using buffered I/O
 **	BinSRead	f  Read binary string
 **	BinWrite	f  Write binary file using unbuffered I/O
 **	BinFWrite	f  Write binary file using buffered I/O
 **	BinSWrite	f  Write binary string
 **
 **	BinReadStruct	f  Read binary file into a C struct using unbuf I/O
 **	BinFReadStruct	f  Read binary file into a C struct using buf I/O
 **	BinSReadStruct	f  Read binary string into a C struct
 **	BinWriteStruct	f  Write binary file from a C struct using unbuf I/O
 **	BinFWriteStruct	f  Write binary file from a C struct using buf I/O
 **	BinSWriteStruct	f  Write binary string from a C struct
 **
 **  PRIVATE CONTENTS
 **	binFileBO	v  current file byte order
 **	binReadMBFDisp	v  array of MBF handling functions
 **	binReadLBFDisp	v  array of LBF handling functions
 **	binReadDisp	v  pointer to the current read function array
 **	binWriteMBFDisp	v  array of MBF handling functions
 **	binWriteLBFDisp	v  array of LBF handling functions
 **	binWriteDisp	v  pointer to the current write function array
 **
 **	binTypeName	v  names of the types
 **	binTypeSize	v  size of each type, as stored by host
 **	binTypeRes	v  resolution of each type, as used by host
 **	binTypeSigned	v  is the type signed?
 **	binTypePad	v  how are types padded?
 **	binTypePadMask	v  how are type's padding addresses masked?
 **
 **	binPadStructxxx 	t  Dummy structures to figure padding
 **	binFloatFormatInfo	t  Floating point format description
 **	binFloatFormatCooked	t  cooked floating point format description
 **	binHostFloatFormat	v  Host floating point format description
 **	binFileFloatFormat	v  File floating point format description
 **
 **	binErrFunc	v  error condition handler function
 **	binOp		v  Current operation (for error handling)
 **
 **	binInit		v  Tables initialized yet?
 **	binInitialize	f  Initialize the tables
 **	binDefaultHandler f  Default error condition handler
 **	binNoHandler	f  No error condition handler
 **
 **	binByteRead	f  read bytes into a buffer
 **	binByteWrite	f  write bytes from a buffer
 **
 **	binReadCharMBF	f  Read into characters from an MBF input
 **	binReadCharLBF	f  Read into characters from an LBF input
 **	binWriteCharMBF	f  Write from characters to MBF output
 **	binWriteCharLBF	f  Write from characters to LBF output
 **
 **	binReadIntMBF	f  Read MBF input into integers
 **	binReadIntLBF	f  Read LBF input into integers
 **	binWriteIntMBF	f  Write from integers to MBF output
 **	binWriteIntLBF	f  Write from integers to LBF output
 **
 **	binReadFloat	f  Read float from input
 **	binWriteFloat	f  Write from float to output
 **
 **  HISTORY
 **	$Log: /roq/libsdsc/bin.c $
 * 
 * 1     11/02/99 4:39p Zaphod
 **	Revision 1.18  1995/06/30  21:52:27  bduggan
 **	added a cast
 **	took  out curses.h
 **
 **	Revision 1.17  1995/06/29  07:19:16  bduggan
 **	changed an unsigned char to an unsigned int (oops.)
 **
 **	Revision 1.17  1995/06/29  07:17:54  bduggan
 **	changed an unsigned char to an inunsigned int
 **
 **	Revision 1.16  1995/06/29  00:17:39  bduggan
 **	updated copyright
 **
 **	Revision 1.15  1995/06/29  00:13:51  bduggan
 **	removed use of 'this', added prototypes
 **
 **	Revision 1.14  1995/04/21  17:56:41  bduggan
 **	Changed bzero to memset, replaced prototypes for
 **	standard functions with include files.
 **
 **	Revision 1.13  1995/04/12  22:27:52  bduggan
 **	Made non-ansi compatible.
 **
 **	Revision 1.12  1994/10/03  16:18:52  nadeau
 **	Built table initializations in to code instead of using external
 **	include files generated by the Makefile.  No longer seems necessary
 **	to generate on-the-fly since the value set is relatively static.
 **	Fixed a bug in reading & writing structures that failed to advance
 **	through memory correctly on non-32-bit architectures.
 **	Updated to ANSI C and C++ compatibility.
 **	Removed all use of register keyword.
 **	Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
 **	Added forward declarations.
 **	Added misc. casts to passify SGI and DEC compilers.
 **	Updated comments.
 **	Updated indenting on some code.
 **	Updated copyright message.
 **
 **	Revision 1.11  92/09/02  13:28:57  vle
 **	Updated copyright notice.
 **	
 **	Revision 1.10  92/03/04  09:19:54  nadeau
 **	Fixed bugs in BinSWriteStruct and BinSReadStruct.  Both were
 **	forgetting to increment the output/input 'data' buffer from
 **	struct field to struct field.  The resulting read and write
 **	operations failed to read or write from the correct locations.
 **	
 **	Revision 1.9  91/12/23  11:43:01  nadeau
 **	Corrected comments.  Optimized code throughout.  Added generic
 **	byte read and write functions to handle I/O to the various
 **	ioType's (fd, fp, and string).  Added support for string read
 **	and write (BinSRead, BinSWrite, etc).  Simplified and reduced
 **	bulky code.
 **	
 **	Revision 1.8  91/10/03  13:06:38  nadeau
 **	Changed binread/binwrite to accept counts of 0 and
 **	just return silently.
 **	
 **	Revision 1.7  91/09/17  19:18:43  nadeau
 **	Misc changes to comments.  Removed some ifdefs for MBF/LBF
 **	handling in favor of a defined BINHOSTBO constant.  Removed
 **	bzero alternate code.  Assume bzero is available.
 **	
 **	Revision 1.6  91/03/11  16:34:23  nadeau
 **	Fixed bug in float write case:  was calling write() when
 **	should have called fwrite().
 **	
 **	Revision 1.5  91/01/09  16:36:52  nadeau
 **	Added BinQError().
 **	
 **	Revision 1.4  90/06/25  10:38:11  ferrerj
 **	Added IBM floating point format.
 **	
 **	Revision 1.3  90/05/16  12:20:45  nadeau
 **	Added code to handle file pointers as well as file descriptors.
 **	Previous code just got the fileno() of the fp and used the file
 **	descriptor code.  This caused problems with data already in the
 **	input/output buffers.
 **	
 **	Revision 1.2  90/04/23  14:11:05  nadeau
 **	Changed BinErrno to BinErrNo.
 **	
 **	Revision 1.1  89/12/14  13:56:57  nadeau
 **	Initial revision
 **	
 **/
/*LINTLIBRARY*/

#include "sdsccopyright.h"
#include <stdlib.h>
#include <stdio.h>
#include "sdsc.h"
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
//#include <unistd.h>

#ifndef NULL
#define NULL	(0)
#endif

#ifndef FALSE
#define FALSE	0
#endif

#ifndef TRUE
#define TRUE	1
#endif

#define BINMAXBUF	(40*sizeof( int ))/* Max size before dynamic alloc*/

#define FPIO		1
#define FDIO		2
#define DATAIO		3

#ifdef MBF
#define BINHOSTBO	BINMBF
#else
#define BINHOSTBO	BINLBF
#endif

#define BINERROR(errno,ret)	{BinErrNo = (errno);return(ret);}



/*
 *  FUNCTION DECLARATIONS
 */

#ifdef __STDC__
static void	binInitialize( void );
static int	binNoHandler( int, int, int, void *, int, int );
static int	binDefaultHandler( int, int, int, void *, int, int );
static int	binByteRead(     int, int, FILE *, unsigned char *, unsigned char *, int );
static int	binByteWrite(    int, int, FILE *, unsigned char *, unsigned char *, int );
static int	binReadCharMBF(  int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binReadCharLBF(  int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binWriteCharMBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binWriteCharLBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binReadIntMBF(   int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binReadIntLBF(   int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binWriteIntMBF(  int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binWriteIntLBF(  int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binReadFloat(    int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
static int	binWriteFloat(   int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
#else

static void	binInitialize( );
static int	binNoHandler( );
static int	binDefaultHandler( );
static int	binByteRead( );
static int	binByteWrite( );
static int	binReadCharMBF( );
static int	binReadCharLBF( );
static int	binWriteCharMBF( );
static int	binWriteCharLBF( );
static int	binReadIntMBF( );
static int	binReadIntLBF( );
static int	binWriteIntMBF( );
static int	binWriteIntLBF( );
static int	binReadFloat( );
static int	binWriteFloat( );
#endif





/*
 *  GLOBAL VARIABLE
 *	BinErrNo	-  error number
 *	BinNErr		-  number of error messages
 *	BinErrList	-  error messages
 *	binErrFunc	-  error condition handler function
 *
 *  DESCRIPTION
 *	On an error, the binary I/O package routines return -1 and set
 *	BinErrNo to an error code.  The programmer may call BinPError
 *	to print the associated error message to stderr, or may do the
 *	message lookup in BinErrList themselves.
 */
int BinErrNo = -1;		/* Bin package error number		*/
char *BinErrList[] =		/* Error message list			*/
{
	/* BINESYS */		"System error:  see errno",
	/* BINETYPE */		"Unknown type selection",
	/* BINENBYTES */	"nBytes cannot be <= 0",
	/* BINECOUNT */		"count cannot be <= 0",
	/* BINEBYTEORDER */	"Unknown file byte order selection",
	/* BINEMALLOC */	"Cannot malloc more host memory",
	/* BINEFLOATFORMAT */	"Unknown floating point format selection",
	/* BINEFLOATUNSUPPORTED*/"Unsupported size for file floating point selection",
};
int BinNErr  = 8;		/* Number of error messages		*/
#ifdef __STDC__
static int (*binErrFunc)( int, int, int, void *, int, int ) = NULL;
				/* Error condition callback func	*/
#else
static int (*binErrFunc)( ) = NULL;
				/* Error condition callback func	*/
#endif






/*
 *  GLOBAL VARIABLE
 *	binTypeName	-  names of the types
 *
 *  DESCRIPTION
 *	To aid in debugging, binTypeName gives the character string name for
 *	a type.
 */
static char *binTypeName[BINNTYPE] =
{
	"pointer",
	"char",
	"unsigned char",
	"short",
	"long",
	"int",
	"int8",
	"int16",
	"int32",
	"unsigned short",
	"unsigned long",
	"unsigned int",
	"unsigned int8",
	"unsigned int16",
	"unsigned int32",
	"boolean",
	"float",
	"double",
	"int64",
	"unsigned int64"
};





/*
 *  GLOBAL VARIABLE
 *	binTypeSize	-  size of each type, as stored by host
 *	binTypeRes	-  resolution of each type, as used by host
 *
 *  DESCRIPTION
 *	binTypeSize holds the size, in bytes, of each type supported
 *	by this package.  The size is defined as the number of bytes
 *	a single item of this type takes up in memory on the host.
 *
 *	binTypeRes holds the resolution, in bytes, of each type.  The
 *	resolution is defined as the number of bytes ** ACTUALLY USED **
 *	by the host in manipulating an item of this type.
 *
 *	On most systems the size of a type and the resolution of a type
 *	are the same.  A 'short' on a SPARCstation takes up 2 bytes of
 *	memory and can hold 2 bytes worth of data (16 bits).  However,
 *	on some systems, most notibly the Cray, the size and resolution of
 *	some types differ.  A 'short' on a CRAY-XMP takes up 8 bytes of
 *	memory but can only hold 3 bytes of data (24 bits).
 *
 *	In processing items we need to know the size of an item so that
 *	we can properly advance through an array of data treated as
 *	unsigned char's.
 *
 *	We need to know the resolution of an item so that we know how
 *	many bytes to put into and take out of a file before padding.
 *
 *	binTypeSize is intialized at compile time.  binTypeRes is
 *	initialized at runtime upon its first usage.
 */
static int binTypeSize[BINNTYPE] =
{
#ifdef __STDC__
	sizeof( void * ),
#else
	sizeof( unsigned char * ),
#endif
	sizeof( char ),
	sizeof( unsigned char ),
	sizeof( short ),
	sizeof( long ),
	sizeof( int ),
	sizeof( sdsc_int8 ),
	sizeof( sdsc_int16 ),
	sizeof( sdsc_int32 ),
	sizeof( unsigned short ),
	sizeof( unsigned long ),
	sizeof( unsigned int ),
	sizeof( sdsc_uint8 ),
	sizeof( sdsc_uint16 ),
	sizeof( sdsc_uint32 ),
	sizeof( sdsc_boolean ),
	sizeof( float ),
	sizeof( double ),
#if LONG_SIZE >= 64
	sizeof( sdsc_int64 ),
	sizeof( sdsc_uint64 )
#else
	0,
	0
#endif
};
static int binTypeRes[BINNTYPE];




/*
 *  GLOBAL VARIABLE
 *	binTypeSigned	-  is the type signed?
 *
 *  DESCRIPTION
 *	binTypeSigned indicates whether a type is signed or not.  Signed
 *	types require sign-extension when they are read into with fewer
 *	bytes than their size, and cause sign-extension when they are
 *	written out into greater bytes than their size.
 *
 *	This array is initialized at compile time.
 */
static int binTypeSigned[BINNTYPE] =
{
	FALSE,
	TRUE,
	FALSE,
	TRUE,
	TRUE,
	TRUE,
	TRUE,
	TRUE,
	TRUE,
	FALSE,
	FALSE,
	FALSE,
	FALSE,
	FALSE,
	FALSE,
	FALSE,
	TRUE,
	TRUE,
	TRUE,
	FALSE
};





/*
 *  TYPEDEF & STRUCTURE
 *	binPadStructxxxx	-  Dummy structure to figure padding
 *
 *  DESCRIPTION
 *	Most compilers pad structures to move integer and float types
 *	to the next word or halfword boundary.  BinReadStruct and
 *	BinWriteStruct must be aware of this padding in order to
 *	properly advance through the input or output buffer to the
 *	next field of a struct to read or write.
 *
 *	These pad structures are only used in the initialization of the
 *	binTypePad[].
 */

#define PADSTRUCT(name,type)					\
typedef struct name						\
{								\
	char bin_c;						\
	type bin_i;						\
} name;


#ifdef __STDC__
PADSTRUCT( binPadStructpointer,	void * )
#else
PADSTRUCT( binPadStructpointer,	unsigned char * )
#endif
PADSTRUCT( binPadStructchar,	char )
PADSTRUCT( binPadStructuchar,	unsigned char )
PADSTRUCT( binPadStructshort,	short )
PADSTRUCT( binPadStructlong,	long )
PADSTRUCT( binPadStructint,	int )
PADSTRUCT( binPadStructint8,	sdsc_int8 )
PADSTRUCT( binPadStructint16,	sdsc_int16 )
PADSTRUCT( binPadStructint32,	sdsc_int32 )
PADSTRUCT( binPadStructushort,	unsigned short )
PADSTRUCT( binPadStructulong,	unsigned long )
PADSTRUCT( binPadStructuint,	unsigned int )
PADSTRUCT( binPadStructuint8,	sdsc_uint8 )
PADSTRUCT( binPadStructuint16,	sdsc_uint16 )
PADSTRUCT( binPadStructuint32,	sdsc_uint32 )
PADSTRUCT( binPadStructboolean,	sdsc_boolean )
PADSTRUCT( binPadStructfloat,	float )
PADSTRUCT( binPadStructdouble,	double )
#if LONG_SIZE >= 64
PADSTRUCT( binPadStructint64,	sdsc_int64 )
PADSTRUCT( binPadStructuint64,	sdsc_uint64 )
#endif
 
#undef PADSTRUCT
 
 


/*
 *  GLOBAL VARIABLE
 *	binTypePad	-  how are types padded?
 *	binTypePadMask	-  how are type's padding addresses masked?
 *
 *  DESCRIPTION
 *	Each entry in this array gives the padding boundary to advance to
 *	for a particular field type when padding structures.  For instance,
 *	on most 32-bit machines, structure fields of type 'short' are padded
 *	to bring them to the next 16-bit boundary, while fields of type
 *	'long' are padded to the next 32-bit boundary.  A structure like
 *	the following:
 *		struct example
 *		{
 *			char c1;
 *			short s;
 *			char c2;
 *			long l;
 *		};
 *	actually occupies space like the following:
 *		struct example
 *		{
 *			char c1;
 *			char pad1;
 *			short s;
 *			char c2;
 *			char pad2[3];
 *			long l;
 *		};
 *
 *	BinReadStruct and BinWriteStruct must know about such padding in
 *	order to properly advance from field to field within the structure.
 *
 *	The above dummy padding structure declarations create one structure
 *	for each supported type.  The structure declares a single character
 *	field, followed by a subject field.  By calculating the difference
 *	in the addresses between these two fields, we get the byte boundary
 *	the type must be padded to.  A value of 1 means no padding.
 *
 *	The binTypePadMask array is an array of address masks, one per type.
 *	The mask is calculated to mask off the relevant bits in a char ptr
 *	that should be 0 for the type's alignment needs.  For instance,
 *	on a byte-addressed machine (like a Sun) that aligns int's to 4-byte
 *	boundaries, the mask would be 0x3.  The mask is used in code like:
 *
 *			if ( ((int)addr & mask) != 0 )
 *				addr = (addr & ~mask) + pad;
 *
 *	The pad and mask tables are both initialized at runtime.
 */
static int binTypePad[BINNTYPE];
static unsigned long binTypePadMask[BINNTYPE];





/*
 *  GLOBAL VARIABLE
 *	binFileBO		-  current file byte order
 *	binReadMBFDisp		-  array of MBF handling functions
 *	binReadLBFDisp		-  array of LBF handling functions
 *	binReadDisp		-  pointer to the current read function array
 *
 *	binWriteMBFDisp		-  array of MBF handling functions
 *	binWriteLBFDisp		-  array of LBF handling functions
 *	binWriteDisp		-  pointer to the current write function array
 *
 *  DESCRIPTION
 *	The output file will be read or written assuming the byte order
 *	is that selected by binFileBO.  The programmer may call BinByteOrder
 *	to change that byte order.
 *
 *	The read and write dispatch tables point to functions to read or
 *	write files in the current byte order.
 *
 *		** MBF and LBF here refer to the byte order **
 *		** of data in the file, not on the host!    **
 *
 *	Each of the read functions read in 'nBytes' bytes from the file, then
 *	save the least-significant bytes into the user's buffer.  When file
 *	data is in MBF form (the default), the least-significant bytes are
 *	the last ones read in.  When file data is in LBF form, the least-
 *	significant bytes are the first ones read in.
 *
 *	Each of the write functions write the 'nBytes' least-significant bytes
 *	of items in the user's buffer to the file.  When file data is to be in
 *	MBF form, the least-significant bytes are the last ones written out.
 *	When file data is to be in LBF form, the least-significant bytes are
 *	the first ones written out.
 *
 *	What's the significance of reading and writing only the 'nBytes'
 *	least-significant bytes?  Consider writing out a 32-bit integer that
 *	is stored in a 64-bit word.  For numbers that take 32-bits or less
 *	to represent, it is the lower 32-bits of the 64-bit word that hold
 *	the value.  For numbers that take more than 32-bits, the number must be
 *	truncated in order to write it out in 32-bits.  Truncation traditionally
 *	happens from the top of the word.  So, writing the least-significant
 *	'nBytes' of each incomming data item handles both cases.  The
 *	situation is similar for reading.
 */

static int binFileBO = BINMBF;	/* File data byte order			*/

#ifdef __STDC__
static int (*binReadMBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
#else
static int (*binReadMBFDisp[])() =
#endif
{
	binReadIntMBF,
	binReadCharMBF,
	binReadCharMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadIntMBF,
	binReadFloat,
	binReadFloat,
#if LONG_SIZE >= 64
	binReadIntMBF,
	binReadIntMBF,
#else
	NULL,
	NULL,
#endif
};
 
#ifdef __STDC__
static int (*binReadLBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
#else
static int (*binReadLBFDisp[])() =
#endif
{
	binReadIntLBF,
	binReadCharLBF,
	binReadCharLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadIntLBF,
	binReadFloat,
	binReadFloat,
#if LONG_SIZE >= 64
	binReadIntLBF,
	binReadIntLBF,
#else
	NULL,
	NULL,
#endif
};
 
#ifdef __STDC__
static int (*binWriteMBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
#else
static int (*binWriteMBFDisp[])() =
#endif
{
	binWriteCharMBF,
	binWriteCharMBF,
	binWriteCharMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteIntMBF,
	binWriteFloat,
	binWriteFloat,
#if LONG_SIZE >= 64
	binWriteIntMBF,
	binWriteIntMBF,
#else
	NULL,
	NULL,
#endif
};
 
#ifdef __STDC__
static int (*binWriteLBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
#else
static int (*binWriteLBFDisp[])() =
#endif
{
	binWriteCharLBF,
	binWriteCharLBF,
	binWriteCharLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteIntLBF,
	binWriteFloat,
	binWriteFloat,
#if LONG_SIZE >= 64
	binWriteIntLBF,
	binWriteIntLBF,
#else
	NULL,
	NULL,
#endif
};

#ifdef __STDC__
static int (**binReadDisp)(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int)  
	= binReadMBFDisp;
static int (**binWriteDisp)(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) 
	= binWriteMBFDisp;
#else
static int (**binReadDisp)()  = binReadMBFDisp;
static int (**binWriteDisp)() = binWriteMBFDisp;
#endif





/*
 *  Host's floating point type.
 */
#if FLOAT_TYPE == IEEE_FLOAT
#define BINHOSTFLOAT	BINIEEE
#endif

#if FLOAT_TYPE == VAX_FLOAT
#define BINHOSTFLOAT	BINVAX
#endif

#if FLOAT_TYPE == VAXG_FLOAT
#define BINHOSTFLOAT	BINVAXG
#endif

#if FLOAT_TYPE == CRAYMP_FLOAT
#define BINHOSTFLOAT	BINCRAYMP
#endif


#ifndef BINHOSTFLOAT
/*
 *  Crash and Burn:
 *	If the host's floating type is unknown, generate a syntax error
 *	to bring the programmer here...
 */
<<<<--+=+ Syntax Error +=+-->>>>	/* Read message below!!!	*/

/*
 *  Programmer!  This syntax error was generated because the floating point
 *  type used by this host is currently unknown by this package.  This
 *  prevents the functioning of code to convert from the host's floating
 *  point format to that of another machine.
 *
 *  Please read the comments describing the 'binFloatFormatInfo' struct and the
 *  initialization of the 'binFloatFormats' array below to learn about
 *  floating point formats and how to set them up for this host.  Please do
 *  not simply default them to something you think is right.  Check and make
 *  sure!  Bugs arising from faulty defaulting can be very hard to find.
 *
 *  When you have a format defined for this host, please forward it to us for
 *  inclusion in a future release of this software.  Thanks!
 */
#endif





/*
 *  STRUCTURE & TYPEDEF
 *	binFloatFormatInfo	-  floating point format description
 *
 *  DESCRIPTION
 *	The binFloatFormatInfo struct describes the attributes of a floating
 *	point format.  The values provided make it possible to generically
 *	convert a float from one format to another.
 *
 *	Floating point numbers have three pieces:
 *		sign		positive or negative flag
 *		exponent	the power to raise the mantissa to
 *		mantissa	the fractional part of the float
 *
 *	The sign is a 1-bit value that indicates if the floating point value
 *	is positive or negative.  Negative floats set the sign bit to a 1.
 *
 *	The exponent is the power to which the float is raised.  The exponent
 *	is "biased" to make it a positive value.  For instance, in IEEE
 *	single-precision, the exponent is 8-bits wide and its bias is 127.
 *	An unbiased 8-bit value can represent a signed value between -127 and
 *	+128, or an unsigned value from 0 to 255.  Biasing the exponent makes
 *	it always positive (unsigned) in representation, yet still allows
 *	negative exponents.  So, with an IEEE bias of 127, the exponent
 *	-10 would be represented as:  -10 + 127 = 117.
 *
 *	The mantissa is the fractional part of the float.  When normallized,
 *	the upper bit of the mantissa is always a 1.  Some formats keep this
 *	1 bit in the float, while others remove it (calling it an implied
 *	bit).
 *
 *	The binFloatFormatInfo struct uses the following fields to describe a
 *	floating point format:
 *
 *		bin_name
 *			The character string name of the format.
 *
 *		bin_number
 *			The #define number associated with this format.
 *
 *		bin_subname
 *			The name of this size of the float.
 *
 *		bin_expBits
 *			The number of bits in the exponent.
 *
 *		bin_mantBits
 *			The number of bits in the mantissa.
 *
 *		bin_expBias
 *			The exponent bias.
 *
 *		bin_mantImplied
 *			Is the implied bit kept in, or removed?
 *
 *		bin_signOverflow
 *			Whether the sign bit is set or not on an overflow.
 *
 *		bin_expOverflow
 *			The value of the exponent on an overflow.
 *
 *		bin_flags
 *			Flag special "exception" conditions in the format:
 *				BINVAXBO	Bizzare VAX float byte order
 *
 *  GENERAL ASSUMPTIONS
 *	The order of fields in a float is:
 *		On MBF systems:
 *			low		  high
 *			sign exponent mantissa
 *		On LBF systems:
 *			low		  high
 *			mantissa exponent sign
 *		Except when BINVAXBO is set in bin_flags, in which case bytes
 *		are swapped every-other to take into account of the VAX's
 *		strange byte ordering of floating point values.
 *
 *	The sign is 1 bit.
 *
 *	There are no unused bits in the float.
 *
 *	(bin_expBits + bin_mantBits + 1) % 8 == 0.
 *
 *	The float is normalized.
 *		
 *  SIGN ASSUMPTIONS
 *	If the sign is a 1, the float is negative.
 *
 *	The sign bit is 0 when the float is 0.
 *
 *  EXPONENT ASSUMPTIONS
 *	The exponent is representable as a signed 32-bit integer on the host.
 *
 *	The exponent is zero when the float is zero.
 *
 *  MANTISSA ASSUMPTIONS
 *	The mantissa is zero when the float is zero.
 *
 *	The mantissa is zero on an overflow.
 *
 *  NON-ASSUMPTIONS (ie, "It is **NOT** assumed that...")
 *	The mantissa is storeable in an integer on the host.
 *
 *	The # of bits in the exponent or mantissa are modulo 8 or that
 *	the exponent starts on a byte boundary.
 *
 *	The redundant high bit of the mantissa on a normalized float is dropped.
 */

typedef struct binFloatFormatInfo
{
	char *bin_name;		/* Name of format			*/
				/*   NULL flags end of list		*/
	int   bin_number;	/* Format number			*/
	char *bin_subname;	/* Name of this size of the format	*/
				/*   NULL flags unusable entry		*/
	int   bin_expBits;	/* Number of bits in exponent		*/
	int   bin_mantBits;	/* Number of bits in mantissa		*/
	int   bin_expBias;	/* Exponent bias			*/
	int   bin_mantImplied;	/* Is implied bit saved in format?	*/
	int   bin_signOverflow;	/*Is sign bit set on overflow?		*/
	unsigned int bin_expOverflow;/* Exponent value on overflow	*/
	int   bin_flags;	/* Excpetion flags			*/
} binFloatFormatInfo;





/*
 *  CONSTANTS
 *	BINVAXBO	-  Bizzare VAX floating point byte order exception
 */

#define BINVAXBO	0x1
		/*	0x2-0x800000	Reserved			*/





/*
 *  GLOBAL VARIABLE
 *	binFloatFormats	-  List of supported floating point formats
 *
 *  DESCRIPTION
 *	The binFloatFormats array of binFloatFormatInfo structs lists the
 *	attributes of each of the floating point formats supported.
 *
 *  TO ADD A NEW FORMAT
 *	1.  Create one or more entries in the array initilaization below.
 *
 *	2.  Make up a name for the format and create a #define BINname in
 *	    bin.raw.h.
 *
 *	3.  Add an #if FLOAT_TYPE for the format to define the BINHOSTFLOAT
 *	    constant on hosts that support that float (the #if's are just
 *	    before the description of the BinFloatFormat struct).
 *
 *	NOTE:  The list is terminated by a NULL pointer in bin_name.
 *	Additionally, a NULL pointer for bin_subname flags that entry as
 *	unusable.
 *
 *	NOTE NOTE:  Different precisions of the same format must be grouped
 *	together!
 */

#ifndef YES
#define YES	1
#endif

#ifndef NO
#define	NO	0
#endif

binFloatFormatInfo binFloatFormats[ ] =
{

/*				      # bits         overflow   	*/
/* name     number     subname  exp mant   bias imp? sgn?  exp     flags*/
{ "IEEE",   BINIEEE,   "single",  8,  23,   127,  NO, YES, 0x0FF,  0 },
{ "IEEE",   BINIEEE,   "double", 11,  52,  1023,  NO, YES, 0x7FF,  0 },
{ "CRAYMP", BINCRAYMP, "single", 15,  48, 16384, YES,  NO, 0x6000, 0 },
{ "VAX",    BINVAX,    "f",       8,  23,   129,  NO, YES, 0,      BINVAXBO },
{ "VAX",    BINVAX,    "d",       8,  55,   129,  NO, YES, 0,      BINVAXBO },
{ "VAX",    BINVAX,    "h",      15, 112, 16385,  NO, YES, 0,      BINVAXBO },
{ "VAXG",   BINVAXG,   "f",       8,  23,   129,  NO, YES, 0,      BINVAXBO },
{ "VAXG",   BINVAXG,   "g",      11,  52,  1025,  NO, YES, 0,      BINVAXBO },
{ "VAXG",   BINVAXG,   "h",      15, 112, 16385,  NO, YES, 0,      BINVAXBO },
#ifdef notdef
{ "IBM",    BINIBM,    "f",       7, 24,     63,  NO, YES, 0,      0 },
#endif
{ NULL,     -1,        NULL,      0,   0,     0,  NO,  NO, 0,      0 },

};





/*
 *  STRUCTURE & TYPEDEF
 *	binFloatFormatCooked	-  cooked floating point format description
 *
 *  DESCRIPTION
 *	The binFloatFormatCooked struct describes the attributes of a floating
 *	point format (as does the BinFloatFormat struct), but also includes
 *	some pre-calculated byte counts, shifts, and masks that help speed
 *	up the conversion algorithm.
 *
 *	The binFloatFormatCooked struct uses these fields to describe the
 *	floating point format:
 *
 *		bin_format
 *			A copy of the data from the binFloatFormatInfo struct.
 *
 *		bin_nbytes
 *			The number of bytes it takes to store this float.
 *
 *		bin_expStartByte
 *		bin_expEndByte
 *			The byte numbers of the first and last bytes
 *			containing exponent bits.
 *
 *		bin_expStartMask
 *		bin_expEndMask
 *			An 8-bit mask to extract only the relevant exponent
 *			bits from the first and last bytes of the exponent.
 *
 *		bin_expShift
 *			The number of bits in the starting byte NOT used
 *			for the exponent (ie, how far to shift the starting
 *			byte left to bring the 1st exponent bit into the
 *			1st bit of the byte).
 *
 *		bin_expMask
 *			A 32-bit mask to apply to an unsigned integer that
 *			will leave only the exponent bits.
 */

typedef struct binFloatFormatCooked
{
	binFloatFormatInfo bin_format;	/* Raw format			*/
	int    bin_nbytes;		/* Size, in bytes, of this entry*/

	int    bin_expStartByte;	/* Byte containing exponent start*/
	int    bin_expEndByte;		/* Byte containing exponent end	*/

	unsigned char bin_expStartMask;	/* Mask for starting exponent byte*/
	unsigned char bin_expEndMask;	/* Mask for ending exponent byte*/
	int    bin_expShift;		/* Shift for starting exponent byte*/
	unsigned int bin_expMask;	/* Mask to just get relevant bits*/
} binFloatFormatCooked;





/*
 *  GLOBAL VARIABLE
 *	binFloatFormatsCooked	-  cooked floating point format descriptions
 *
 *  DESCRIPTION
 *	The binFloatFormatsCooked array gives the "cooked" (after pre-calc)
 *	version of the data in the binFloatFormats array.  It is the
 *	cooked version of the data that is actually used by the floating
 *	point conversion code.
 *
 *	This array is initialized at startup by binInitialize().
 */
binFloatFormatCooked binFloatFormatsCooked[sizeof(binFloatFormats)/sizeof(binFloatFormatInfo)];





/*
 *  GLOBAL VARIABLE
 *	binHostFloatFormat	-  Host floating point format description
 *	binFileFloatFormat	-  File floating point format description
 *
 *  DESCRIPTION
 *	binHostFloatFormat points to the set of floating point format
 *	descriptions appropriate for the host.
 *
 *	binFileFloatFormat points to the set of floating point format
 *	descriptions selected for the file.
 *
 *	Both of these globals are initialized at startup by binInitialize().
 */
binFloatFormatCooked *binFileFloatFormat = NULL;
binFloatFormatCooked *binHostFloatFormat = NULL;





/*
 *  GLOBAL VARIABLE
 *	binOp			-  Current operation
 *
 *  DESCRIPTION
 *	Each of the top level read or write functions set binOp to the
 *	operation type being done so that, should an error occur, the
 *	user's error handler can be told what operation was in progress.
 */
static int binOp;		/* Current operation (for error handling)*/



#ifdef __STDC__
static int	binConvertFloat( int, binFloatFormatCooked *, int, int, unsigned char *, binFloatFormatCooked *, int, int, unsigned char *, int );
#else
static int	binConvertFloat( );
#endif





/*
 *  FUNCTION
 *	binInit		-  tables initialized yet?
 *	binInitialize	-  Initialize the tables
 *
 *  DESCRIPTION
 *	This routine initializes the tables:
 *		binTypeRes	-  type resolution
 *		binTypePad	-  type structure field padding
 *		binTypePadMask	-  type padding address masks
 *		binFloatFormatsCooked -  cooked float information
 *
 *	determines the floating point type of the host:
 *		binHostFloatFormat	-  host format selection
 *
 *	and the default floating point type for the file:
 *		binFileFloatFormat	-  file format selection
 *
 *	The resolution table indicates the number of bytes in a type that
 *	are actually available for storing data, as opposed to the number
 *	of bytes the type occupies in memory.  On most machines these
 *	two values are the same.  A notible exception is the CRAY's 'short'
 *	which occupies 8 bytes in memory, but can only hold a 3 byte value.
 *
 *	The padding table indicates how the various types are padded when
 *	they occur as fields in a structure.  To initialize the table we
 *	compute the difference between a char structure field's address
 *	and the address of a field of the desired type.  If padding has
 *	taken place, the difference will be greater than 1 byte.
 *
 *	Many machines require that all integer or floating point accesses
 *	be made at boundaries that are a multiple of the item size.  For
 *	instance, on a SPARCstation all 32-bit integers must be on 32-bit
 *	boundaries, and all 16-bit integers on 16-bit boundaries.  Accesses
 *	that are not word aligned cause a bus error.
 *
 *	Compilers for machines that do not require word alignment may still
 *	do structure padding, such as the VAX ULTRIX compiler.
 *
 *	Still other compilers do no structure padding, such as the VAX
 *	VMS compiler.
 *
 *	The Cooked formats table includes the basic floating point format
 *	information from binFloatFormats[], plus various masks and byte
 *	counts to make floating point conversions easier and quicker.
 */

static int binInit = FALSE;

static void			/* Returns nothing			*/
#ifdef __STDC__
binInitialize( void )
#else
binInitialize( )
#endif
{
	int *br = binTypeRes;	/* Pointer to Res table			*/
	int *bp = binTypePad;	/* Pointer to Pad table			*/
	unsigned long charbit;	/* Address bit for byte addressing	*/
	unsigned long shiftbit;	/* How far to shift to get to charbit	*/
	int i;			/* Counter				*/
	binFloatFormatInfo *fp;	/* Float format table pointer		*/
	binFloatFormatCooked *fcp;/* Cooked format table pointer	*/
	int nbits;		/* Number of extra bits in byte		*/
	binPadStructpointer	structpointer;
	binPadStructchar	structchar;
	binPadStructuchar	structuchar;
	binPadStructshort	structshort;
	binPadStructlong	structlong;
	binPadStructint		structint;
	binPadStructint8	structint8;
	binPadStructint16	structint16;
	binPadStructint32	structint32;
	binPadStructushort	structushort;
	binPadStructulong	structulong;
	binPadStructuint	structuint;
	binPadStructuint8	structuint8;
	binPadStructuint16	structuint16;
	binPadStructuint32	structuint32;
	binPadStructboolean	structboolean;
	binPadStructfloat	structfloat;
	binPadStructdouble	structdouble;
#if LONG_SIZE >= 64
	binPadStructint64	structint64;
	binPadStructuint64	structuint64;
#endif

	/*
	 *  Initialize the resolution table.
	 */

#define DEF(type)			\
{					\
	type var = ((type)1)<<(8*sizeof(type)-2);\
	var <<= 1;			\
	if ( var != ((type)0) )		\
		*br++ = sizeof(type);	\
	else				\
	{				\
		int ii = 1;		\
		for ( var = ((type)1); var != ((type)0); var <<= 1 )\
			ii++;		\
		*br++ = ii>>3;		\
	}				\
}
	*br++ = 0;	/* skip pointer */
	DEF(char)
	DEF(unsigned char)
	DEF(short)
	DEF(long)
	DEF(int)
	DEF(sdsc_int8)
	DEF(sdsc_int16)
	DEF(sdsc_int32)
	DEF(unsigned short)
	DEF(unsigned long)
	DEF(unsigned int)
	DEF(sdsc_uint8)
	DEF(sdsc_uint16)
	DEF(sdsc_uint32)
	DEF(sdsc_boolean)
	*br++ = 0;	/* skip float */
	*br++ = 0;	/* skip double */
#if LONG_SIZE >= 64
	DEF(sdsc_int64)
	DEF(sdsc_uint64)
#else
	*br++ = 0;
	*br++ = 0;
#endif
 
#undef DEF


	/*
	 *  Initialize the structure padding table.
	 */
	*bp++ = (char *)&structpointer.bin_i-&structpointer.bin_c;
	*bp++ = (char *)&structchar.bin_i-&structchar.bin_c;
	*bp++ = (char *)&structuchar.bin_i-&structuchar.bin_c;
	*bp++ = (char *)&structshort.bin_i-&structshort.bin_c;
	*bp++ = (char *)&structlong.bin_i-&structlong.bin_c;
	*bp++ = (char *)&structint.bin_i-&structint.bin_c;
	*bp++ = (char *)&structint8.bin_i-&structint8.bin_c;
	*bp++ = (char *)&structint16.bin_i-&structint16.bin_c;
	*bp++ = (char *)&structint32.bin_i-&structint32.bin_c;
	*bp++ = (char *)&structushort.bin_i-&structushort.bin_c;
	*bp++ = (char *)&structulong.bin_i-&structulong.bin_c;
	*bp++ = (char *)&structuint.bin_i-&structuint.bin_c;
	*bp++ = (char *)&structuint8.bin_i-&structuint8.bin_c;
	*bp++ = (char *)&structuint16.bin_i-&structuint16.bin_c;
	*bp++ = (char *)&structuint32.bin_i-&structuint32.bin_c;
	*bp++ = (char *)&structboolean.bin_i-&structboolean.bin_c;
	*bp++ = (char *)&structfloat.bin_i-&structfloat.bin_c;
	*bp++ = (char *)&structdouble.bin_i-&structdouble.bin_c;
#if LONG_SIZE >= 64
	*bp++ = (char *)&structint64.bin_i-&structint64.bin_c;
	*bp++ = (char *)&structuint64.bin_i-&structuint64.bin_c;
#else
	*bp++ = -1;
	*bp++ = -1;
#endif


	/*
	 *  Initialize the structure padding mask table.
	 */
	charbit = (unsigned long)((char *)&i + 1) - (unsigned long)(char *)&i;
	for ( shiftbit = ((unsigned long)(-1)); charbit != 0; shiftbit++ )
		charbit >>= 1;
	for ( i = 0; i < BINMAXTYPE; i++ )
		binTypePadMask[i] = ((unsigned long)(binTypePad[i]-1))<<shiftbit;


	/*
	 *  Initialize the cooked floating point format table.
	 */
	for ( fp = binFloatFormats, fcp = binFloatFormatsCooked;
		fp->bin_name != NULL; fp++, fcp++ )
	{
		fcp->bin_format = *fp;
		fcp->bin_nbytes = (fp->bin_expBits + fp->bin_mantBits + 1)/8;

		if ( (fp->bin_expBits + fp->bin_mantBits + 1) % 8 != 0 )
		{
			/* Illegal entry.				*/
			fcp->bin_format.bin_subname = NULL;
			continue;
		}

		fcp->bin_expStartByte = fp->bin_mantBits / 8;
		fcp->bin_expShift     = nbits = fp->bin_mantBits % 8;
		fcp->bin_expStartMask = (unsigned char) (((unsigned long)0xFF) << nbits);

		/* Assume last byte is end byte and last bit is sign.	*/
		fcp->bin_expEndByte = fcp->bin_nbytes - 1;
		fcp->bin_expEndMask = (unsigned char)((unsigned long)0x7F);
		fcp->bin_expMask = (unsigned int) (~( (~((unsigned long)0)) << fp->bin_expBits));
	}


	/*
	 *  Initialize the host and file floating point format selections.
	 */
	for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
	{
		if ( fcp->bin_format.bin_number == BINHOSTFLOAT )
		{
			binHostFloatFormat = fcp;
			break;
		}
	}
	if ( binFileFloatFormat == NULL )
	{
		for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
		{
			if ( fcp->bin_format.bin_number == BINIEEE )
			{
				binFileFloatFormat = fcp;
				break;
			}
		}
	}

	binErrFunc = binDefaultHandler;

	binInit = TRUE;
}





/*
 *  FUNCTION
 *	BinQMachine	-  query machine characteristics
 *
 *  DESCRIPTION
 *	The tables are initialized, if not done already, and a static
 *	BinMachineInfo struct set up.  A pointer to the info is returned.
 */

static BinMachineInfo binMachine;	/* Machine info struct		*/


BinMachineInfo *			/* Returns ptr to info struct	*/
#ifdef __STDC__
BinQMachine( void )
#else
BinQMachine( )
#endif
{
	if ( !binInit )
		binInitialize( );

	memset( (void *)&binMachine, 0x00, sizeof (binMachine) );

#ifdef VENDOR_NAME
	binMachine.bin_vendorName = VENDOR_NAME;
#else
	binMachine.bin_vendorName = "Unknown";
#endif

#ifdef MACHINE_NAME
	binMachine.bin_machineName = MACHINE_NAME;
#else
	binMachine.bin_machineName = "Unknown";
#endif

#ifdef CPU_NAME
	binMachine.bin_cpuName = CPU_NAME;
#else
	binMachine.bin_cpuName = "Unknown";
#endif

#ifdef OS_NAME
	binMachine.bin_osName = OS_NAME;
#else
	binMachine.bin_osName = "Unknown";
#endif

	binMachine.bin_byteOrder = BINHOSTBO;
#ifdef MBF
	binMachine.bin_byteOrderName = "MBF";
#else
	binMachine.bin_byteOrderName = "LBF";
#endif

	binMachine.bin_floatFormat= BINHOSTFLOAT;
	binMachine.bin_floatFormatName = binHostFloatFormat->bin_format.bin_name;

	binMachine.bin_typeSize   = binTypeSize;
	binMachine.bin_typeSigned = binTypeSigned;
	binMachine.bin_typeRes    = binTypeRes;
	binMachine.bin_typePad    = binTypePad;
	binMachine.bin_typeName   = binTypeName;
	binMachine.bin_typePadMask= binTypePadMask;

	return ( &binMachine );
}





/*
 *  FUNCTION
 *	BinPError	-  Print error message
 *
 *  DESCRIPTION
 *	The error text associated with the current BinErrNo is printed
 *	to stderr, preceded by the given leader string.
 */

void				/* Returns nothing			*/
#ifdef __STDC__
BinPError( char *s )
#else
BinPError( s )
	char *s;		/* Leader string			*/
#endif
{
	if ( BinErrNo == BINESYS )
		perror( s );
	else if ( BinErrNo < 0 || BinErrNo >= BinNErr )
		(void)fprintf( stderr, "Unknown error\n" );
	else if ( s && *s )
		(void)fprintf( stderr, "%s: %s\n", s, BinErrList[BinErrNo] );
	else
		(void)fprintf( stderr, "%s\n", BinErrList[BinErrNo] );
}





/*
 *  FUNCTION
 *	BinQError	-  Query error message
 *
 *  DESCRIPTION
 *	The error text associated with the current BinErrNo is returned.
 */

extern int errno;			/* System call error code	*/
extern int sys_nerr;			/* # of system call error codes	*/
extern char *sys_errlist[];		/* Error code message strings	*/

char *					/* Returns error text		*/
#ifdef __STDC__
BinQError( void )
#else
BinQError( )
#endif
{
	if ( BinErrNo == BINESYS )
	{
		if ( errno < 0 || errno >= sys_nerr )
			return ( "Unknown error" );
		return ( sys_errlist[errno] );
	}
	if ( BinErrNo < 0 || BinErrNo >= BinNErr )
		return ( "Unknown error" );
	return ( BinErrList[BinErrNo] );
}





/*
 *  FUNCTION
 *	BinErrorHandler		-  nominate an error condition handler func
 *	binDefaultHandler	-  Default error condition handler
 *	binNoHandler		-  No error condition handler
 *
 *  DESCRIPTION
 *	On errors in integer and floating point format conversion we call the
 *	nominated error condition callback function.  By default it is set to
 *	our own stderr printing function.  The user may override this by
 *	nominating his/her own function.
 */

void					/* Returns nothing		*/
#ifdef __STDC__
BinErrorHandler( int (*func)(int , int , int , void *, int , int ) )
#else
BinErrorHandler( func )
	int (*func)();			/* Function to nominate		*/
#endif
{
	if ( func == BINDEFFUNC )
		binErrFunc = binDefaultHandler;
	else if ( func == BINNOFUNC )
		binErrFunc = binNoHandler;
	else
		binErrFunc = func;
	return;
}

static int
#ifdef __STDC__
binNoHandler( int fd, int op, int reason, void *data, int frombits, int tobits )
#else
binNoHandler( fd, op, reason, data, frombits, tobits )
	int fd;				/* File descriptor		*/
	int op;				/* Current operation		*/
	int reason;			/* Error reason code		*/
	unsigned char *data;		/* Data holding bad value	*/
	int frombits;			/* Max # bits in type comming from*/
	int tobits;			/* Max # bits in type going to	*/
#endif
{
	return ( 0 );
}

static int				/* Returns nothing		*/
#ifdef __STDC__
binDefaultHandler( int fd, int op, int reason, void *data, int frombits, int tobits )
#else
binDefaultHandler( fd, op, reason, data, frombits, tobits )
	int fd;				/* File descriptor		*/
	int op;				/* Current operation		*/
	int reason;			/* Error reason code		*/
	unsigned char *data;		/* Data holding bad value	*/
	int frombits;			/* Max # bits in type comming from*/
	int tobits;			/* Max # bits in type going to	*/
#endif
{
	char opname[100];		/* Operation name		*/
	int  nBytes;			/* Number of bytes		*/
	unsigned char *pData;		/* Data byte pointer		*/

	switch ( op )
	{
	case BINOPREAD:
		(void)sprintf( opname, "read of file %d", fd );
		break;
	case BINOPWRITE:
		(void)sprintf( opname, "write of file %d", fd );
		break;
	case BINOPREADSTRUCT:
		(void)sprintf( opname, "structure read of file %d", fd );
		break;
	case BINOPWRITESTRUCT:
		(void)sprintf( opname, "structure write of file %d", fd );
		break;
	case BINOPCONVERTFLOAT:
		(void)sprintf( opname, "floating point conversion" );
		break;
	default:
		(void)sprintf( opname, "unknown operation" );
		break;
	}

	nBytes = frombits / 8;
	if ( frombits % 8 != 0 )
		nBytes++;

	pData = (unsigned char *)data;
	switch ( reason )
	{
	case BINEINTEGERTRUNC:	/* Integer truncation occurred		*/
		(void)fprintf( stderr, "Bin:  integer truncation during %s\n",
			opname );
		(void)fprintf( stderr, "  %d bit integer truncated on storage into %d bit integer\n",
			frombits, tobits );
		(void)fprintf( stderr, "  Pre-truncation integer = 0x" );
		do
			(void)fprintf( stderr, "%02x", (int)*(pData++) );
		while ( --nBytes );
		(void)fprintf( stderr, "\n" );
		return ( 0 );

	case BINEFLOATOVERFLOW:	/* Floating point overflow occurred	*/
		(void)fprintf( stderr, "Bin:  floating point overflow during %s\n",
			opname );
		(void)fprintf( stderr, "  %d bit exponent overflows when reduced to %d bits\n",
			frombits, tobits );
		(void)fprintf( stderr, "  Pre-overflow float = 0x" );
		do
			(void)fprintf( stderr, "%02x", (int)*(pData++) );
		while ( --nBytes );
		(void)fprintf( stderr, "\n" );
		return ( 0 );

	case BINEFLOATUNDERFLOW:/* Floating point underflow occurred	*/
		(void)fprintf( stderr, "Bin:  floating point underflow during %s\n",
			opname );
		(void)fprintf( stderr, "  %d bit exponent underflows when reduced to %d bits\n",
			frombits, tobits );
		(void)fprintf( stderr, "  Pre-underflow float = 0x" );
		do
			(void)fprintf( stderr, "%02x", (int)*(pData++) );
		while ( --nBytes );
		(void)fprintf( stderr, "\n" );
		return ( 0 );

	default:		/* Unknown!?				*/
		(void)fprintf( stderr, "Bin:  unknown error has occurred during %s\n",
			opname );
		return ( 0 );
	}
}





/*
 *  FUNCTION
 *	BinByteOrder	-  Select the byte order of the file
 *	BinQByteOrder	-  Query the byte order of the file
 *
 *  DESCRIPTION
 *	The byte order of the data in the file must be known in order to
 *	handle conversion of data to the byte order of the host.  The
 *	default is MBF (Most-Significant Byte First).
 *
 *	BinByteOrder sets the byte order and returns -1 or 0.
 *
 *	BinQByteOrder queries the byte order.
 */

int				/* Returns status			*/
#ifdef __STDC__
BinByteOrder( int which )
#else
BinByteOrder( which )
	int which;		/* Which byte order to use		*/
#endif
{
	if ( !binInit )
		binInitialize( );

	switch ( which )
	{
	case BINMBF:
		binFileBO    = BINMBF;
		binReadDisp  = binReadMBFDisp;
		binWriteDisp = binWriteMBFDisp;
		return ( 0 );

	case BINLBF:
		binFileBO    = BINLBF;
		binReadDisp  = binReadLBFDisp;
		binWriteDisp = binWriteLBFDisp;
		return ( 0 );

	default:
		BINERROR( BINEBYTEORDER, -1 );
	}
}

int				/* Returns current byte order		*/
#ifdef __STDC__
BinQByteOrder( void )
#else
BinQByteOrder( )
#endif
{
	if ( !binInit )
		binInitialize( );

	return ( binFileBO );
}





/*
 *  FUNCTION
 *	BinFloatFormat	-  Select the floating point format of the file
 *	BinQFloatFormat	-  Query the floating point format of the file
 *
 *  DESCRIPTION
 *	The floating format for data in the file must be known in order to
 *	handle conversion of data to the float format of the host.  The
 *	default is IEEE.
 *
 *	BinFloatFormat sets the floating point format and returns -1 or 0.
 *
 *	BinQFloatFormat queries the floating point format.
 */

int				/* Returns status			*/
#ifdef __STDC__
BinFloatFormat( int which )
#else
BinFloatFormat( which )
	int which;		/* Which floating point format to use	*/
#endif
{
	binFloatFormatCooked *fcp;/* Cooked table pointer		*/

	if ( !binInit )
		binInitialize( );

	for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
		if ( fcp->bin_format.bin_number == which )
			break;
	if ( fcp->bin_format.bin_name == NULL )
		BINERROR( BINEFLOATFORMAT, -1 );	/* Unknown	*/
	binFileFloatFormat = fcp;
	return ( 0 );
}

int				/* Returns current float format		*/
#ifdef __STDC__
BinQFloatFormat( void )
#else
BinQFloatFormat( )
#endif
{
	if ( !binInit )
		binInitialize( );

	return ( binFileFloatFormat->bin_format.bin_number );
}





#define BINCHECKRTYPE(type)						\
	if ( (type) <= 0 || (type) > BINMAXTYPE || binReadDisp[(type)] == NULL)\
		BINERROR( BINETYPE, -1 );


#define BINCHECKWTYPE(type)						\
	if ( (type) <= 0 || (type) > BINMAXTYPE || binWriteDisp[(type)] ==NULL)\
		BINERROR( BINETYPE, -1 );


#define BINCHECKNBYTES(nBytes)						\
	if ( (nBytes) <= 0 )						\
		BINERROR( BINENBYTES, -1 );


#define BINCHECKCOUNT(count)						\
	if ( (count) == 0 )						\
		return ( 0 );						\
	if ( (count) < 0 )						\
		BINERROR( BINECOUNT, -1 );





/*
 *  FUNCTION
 *	BinRead		-  Read binary file using unbuffered I/O
 *	BinFRead	-  Read binary file using buffered I/O
 *	BinSRead	-  Read binary string
 *	BinWrite	-  Write binary file using unbuffered I/O
 *	BinFWrite	-  Write binary file using buffered I/O
 *	BinSWrite	-  Write binary string
 *
 *  DESCRIPTION
 *	The incomming arguments are checked for legality.  If any are
 *	bad, a -1 is returned and the global error variable 'BinErrNo'
 *	set to an appropriate error code.
 *
 *	Based on the user's 'type', an appropriate read or write function is
 *	called through the read or write dispatch tables.  The dispatch tables
 *	point to LBF or MBF functions, as selected by an earlier user
 *	call to BinByteOrder.
 */

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinRead( int fd, void *buf, int type, int nBytes, int count )
#else
BinRead( fd, buf, type, nBytes, count )
	int fd;				/* File descriptor		*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to read		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)(  );	/* Dispatch table entry		*/
#endif
	BINCHECKRTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPREAD;
	dispatch = binReadDisp[type];
	return ( (*dispatch)( FDIO, fd, (FILE *)NULL, (unsigned char *)NULL,
		(unsigned char*) buf, type, nBytes, count ) );
}

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinFRead( FILE *fp, void *buf, int type, int nBytes, int count )
#else
BinFRead( fp, buf, type, nBytes, count )
	FILE *fp;			/* File pointer			*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to read		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)(  );	/* Dispatch table entry		*/
#endif
	BINCHECKRTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPREAD;
	dispatch = binReadDisp[type];
	return ( (*dispatch)( FPIO, -1, fp,
		(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
}

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinSRead( unsigned char *data, void *buf, int type, int nBytes, int count )
#else
BinSRead( data, buf, type, nBytes, count )
	unsigned char *data;		/* Input data			*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to read		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif
	BINCHECKRTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPREAD;
	dispatch = binReadDisp[type];
	return ( (*dispatch)( DATAIO, -1, (FILE *)NULL,
		data, (unsigned char*) buf, type, nBytes, count ) );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinWrite( int fd, void *buf, int type, int nBytes, int count )
#else
BinWrite( fd, buf, type, nBytes, count )
	int fd;				/* File descriptor		*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to write		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)(  );	/* Dispatch table entry		*/
#endif
	BINCHECKWTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPWRITE;
	dispatch = binWriteDisp[type];
	return ( (*dispatch)( FDIO, fd, (FILE *)NULL,
		(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinFWrite( FILE *fp, void *buf, int type, int nBytes, int count )
#else
BinFWrite( fp, buf, type, nBytes, count )
	FILE *fp;			/* File pointer			*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to write		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)(  );	/* Dispatch table entry		*/
#endif
	BINCHECKWTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPWRITE;
	dispatch = binWriteDisp[type];
	return ( (*dispatch)( FPIO, -1, fp,
		(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinSWrite( unsigned char *data, void *buf, int type, int nBytes, int count )
#else
BinSWrite( data, buf, type, nBytes, count )
	unsigned char *data;		/* Output data			*/
	unsigned char *buf;		/* Data buffer			*/
	int type;			/* Buffer variable's type	*/
	int nBytes;			/* # of bytes when in file	*/
	int count;			/* # of items to write		*/
#endif
{
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)(  );	/* Dispatch table entry		*/
#endif
	BINCHECKWTYPE(  type );
	BINCHECKNBYTES( nBytes );
	BINCHECKCOUNT(  count );

	if ( !binInit )
		binInitialize( );

	binOp = BINOPWRITE;
	dispatch = binWriteDisp[type];
	return ( (*dispatch)( DATAIO, -1, (FILE *)NULL,
		data, (unsigned char*) buf, type, nBytes, count ) );
}





/*
 *  FUNCTION
 *	BinReadStruct	-  Read binary file into a C struct using unbuf I/O
 *	BinFReadStruct	-  Read binary file into a C struct using buf I/O
 *	BinSReadStruct	-  Read binary string into a C struct
 *	BinWriteStruct	-  Write binary file from a C struct using unbuf I/O
 *	BinFWriteStruct	-  Write binary file from a C struct using buf I/O
 *	BinSWriteStruct	-  Write binary string from a C struct
 *
 *  DESCRIPTION
 *	The incomming arguments are checked for legality.  If any are
 *	bad, a -1 is returned and the global error variable 'BinErrNo'
 *	set to an appropriate error code.
 *
 *	The structure description array is walked and the appropriate
 *	single type read or write function called through the read or write
 *	dispatch tables.  The dispatch tables point to LBF or MBF functions,
 *	as selected by an earlier user call to BinByteOrder( ).
 *
 *	Structure field padding is done per the host system's characteristics.
 *	For instance, on most 32-bit workstations, short's are aligned to
 *	16-bit boundaries, and int's and long's to 32-bit boundaries.
 */

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinReadStruct( int fd, void *buf, BinField *fields )
#else
BinReadStruct( fd, buf, fields )
	int fd;				/* File descriptor		*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes read		*/
	int n;				/* Read status & # bytes read	*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKRTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes )
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the reads.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPREADSTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binReadDisp[bfp->bin_type];
		if ( (n = (*dispatch)( FDIO, fd, (FILE *)NULL,
			(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;
		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinFReadStruct( FILE *fp, void *buf, BinField *fields )
#else
BinFReadStruct( fp, buf, fields )
	FILE *fp;			/* File pointer			*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes read		*/
	int n;				/* Read status & # bytes read	*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKRTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes )
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the reads.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPREADSTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binReadDisp[bfp->bin_type];
		if ( (n = (*dispatch)( FPIO, -1, fp,
			(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;
		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}

int					/* Returns # of bytes read	*/
#ifdef __STDC__
BinSReadStruct( unsigned char *data, void *buf, BinField *fields )
#else
BinSReadStruct( data, buf, fields )
	unsigned char *data;		/* Input data			*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes read		*/
	int n;				/* Read status & # bytes read	*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKRTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes )
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the reads.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPREADSTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binReadDisp[bfp->bin_type];
		if ( (n = (*dispatch)( DATAIO, -1, (FILE *)NULL,
			data, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;
		data     += bfp->bin_nbytes * bfp->bin_count;
		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinWriteStruct( int fd, void *buf, BinField *fields )
#else
BinWriteStruct( fd, buf, fields )
	int fd;				/* File descriptor		*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes written	*/
	int n;				/* Read status & # bytes written*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKWTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes );
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the writes.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPWRITESTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *) ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binWriteDisp[bfp->bin_type];
		if ( (n = (*dispatch)( FDIO, fd, (FILE *)NULL,
			(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;

		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinFWriteStruct( FILE *fp, void *buf, BinField *fields )
#else
BinFWriteStruct( fp, buf, fields )
	FILE *fp;			/* File pointer			*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes written	*/
	int n;				/* Read status & # bytes written*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKWTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes );
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the writes.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPWRITESTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binWriteDisp[bfp->bin_type];
		if ( (n = (*dispatch)( FPIO, -1, fp,
			(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;
		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}

int					/* Returns # of bytes written	*/
#ifdef __STDC__
BinSWriteStruct( unsigned char *data, void *buf, BinField *fields )
#else
BinSWriteStruct( data, buf, fields )
	unsigned char *data;		/* Output data			*/
	unsigned char *buf;		/* Data buffer			*/
	BinField *fields;		/* Structure field description	*/
#endif
{
	BinField *bfp;			/* Field pointer		*/
	int nBytes = 0;			/* Number of bytes written	*/
	int n;				/* Read status & # bytes written*/
	unsigned long ptrAsInt;		/* Pointer cast as int for math	*/
#ifdef __STDC__
	int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
		int, int, int );	/* Dispatch table entry		*/
#else
	int (*dispatch)( );	/* Dispatch table entry		*/
#endif

	/*
	 *  Check all values in the fields array before doing anything.
	 */
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		BINCHECKWTYPE(  bfp->bin_type );
		BINCHECKNBYTES( bfp->bin_nbytes );
	}

	if ( !binInit )
		binInitialize( );


	/*
	 *  Now execute the writes.
	 *
	 *  This is potentially confusing code, so here's what's happening:
	 *
	 *	-  If the buf pointer is not currently at the next address
	 *	   needed based upon the host's struct padding characteristics,
	 *	   then we need to move it there.
	 *
	 *	-  To do that check we need to do some arithmetic on the
	 *	   buf pointer as an integer.  This requires that we cast it
	 *	   to an integer type (unsigned long).  We assume that an
	 *	   unsigned long is big enough to hold a pointer (!!!).
	 *
	 *	-  As a quick check, we mask off the lower bits of the address
	 *	   based upon the binTypePadMask[] value for the type.  This
	 *	   tells us fast if the buf pointer needs aligning or not.
	 *
	 *	-  Say we need to align.  To do so we need to get rid of those
	 *	   lower bits, then add the right amount to leap to the next
	 *	   alignment point for the address.  This is type dependent.
	 *	   The distance to leap is the pad amount for the type and is
	 *	   contained in binTypePad[].  The amount to mask off is again
	 *	   in binTypePadMask[].  Because we're doing arithmetic, we
	 *	   need to cast the buf pointer as an integer (unsigned long)
	 *	   to do the math.
	 *
	 *  That's it.
	 */
	binOp = BINOPWRITESTRUCT;
	for ( bfp = fields; bfp->bin_count; bfp++ )
	{
		ptrAsInt = (unsigned long)buf;
		ptrAsInt &= binTypePadMask[bfp->bin_type];
		if ( ptrAsInt != (unsigned long)0 )
		{
			/* Then we need to align the pointer.		*/
			ptrAsInt  = (unsigned long)buf;
			ptrAsInt &= ~binTypePadMask[bfp->bin_type];
			buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
		}
		dispatch = binWriteDisp[bfp->bin_type];
		if ( (n = (*dispatch)( DATAIO, -1, (FILE *)NULL,
			data, (unsigned char*) buf, bfp->bin_type,
			bfp->bin_nbytes, bfp->bin_count )) == -1 )
			return ( -1 );		/* Error occured	*/
		nBytes   += n;
		data     += bfp->bin_nbytes * bfp->bin_count;
		buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
	}
	return ( nBytes );
}





/*
 *  FUNCTION
 *	binByteRead	-  read bytes into a buffer
 *	binByteWrite	-  write bytes from a buffer
 *
 *  DESCRIPTION
 *	binByteRead:	N bytes of data are read in from a file descriptor,
 *	file pointer, or data buffer.
 *
 *	binByteWrite:	N bytes of data are written to a file descriptor,
 *	file pointer, or data buffer.
 *
 *	When reading from or writing to file descriptors or file pointers,
 *	we loop on the read or write in order to block, even on non-blocking
 *	I/O connections, such as pipes and sockets.
 */

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binByteRead( int ioType, int fd, FILE *fp, unsigned char *data, unsigned char *buffer, int n )
#else
binByteRead( ioType, fd, fp, data, buffer, n )
	int   ioType;			/* Where to get data		*/
	int   fd;			/* File descriptor		*/
	FILE *fp;			/* File pointer			*/
	unsigned char *data;		/* Input data			*/
	unsigned char *buffer;		/* Output data			*/
	int   n;			/* # of bytes to read		*/
#endif
{
	int cnt;			/* Counter			*/
	int nBytes;			/* # of bytes read in at once	*/
	unsigned char *pBuffer;		/* Buffer pointer		*/

	switch ( ioType )
	{
	case FDIO:	/* File descriptor.				*/
		for ( cnt = 0, pBuffer = buffer; cnt != n; )
		{
			switch ( (nBytes = read( fd, pBuffer, n-cnt )) )
			{
			case 0:	/* EOF reached.				*/
				return ( cnt );
			case -1:/* Error.				*/
				BINERROR( BINESYS, -1 );
			default:
				pBuffer += nBytes;
				cnt     += nBytes;
				break;
			}
		}
		return ( cnt );

	case FPIO:	/* File pointer.				*/
		for ( cnt = 0, pBuffer = buffer; cnt != n; )
		{
			switch ( (nBytes = fread( (char *)pBuffer, 1, n-cnt, fp )) )
			{
			case 0:	/* EOF or error reached.		*/
				return ( cnt );
			default:
				pBuffer += nBytes;
				cnt     += nBytes;
				break;
			}
		}
		return ( cnt );

	case DATAIO:	/* Data buffer.					*/
		memcpy( (void*)buffer, (void*)data, n);
		return ( n );
	}
	return( 0 );
	/*NOTREACHED*/
}

static int				/* Returns # of bytes written	*/
#ifdef __STDC__
binByteWrite( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buffer, int n )
#else
binByteWrite( ioType, fd, fp, data, buffer, n )
	int   ioType;			/* Where to send data		*/
	int   fd;			/* File descriptor		*/
	FILE *fp;			/* File pointer			*/
	unsigned char *data;		/* Output data			*/
	unsigned char *buffer;		/* Input data			*/
	int   n;			/* # of bytes to write		*/
#endif
{
	int cnt;			/* Counter			*/
	int nBytes;			/* # of bytes read in at once	*/
	unsigned char *pBuffer;		/* Buffer pointer		*/

	switch ( ioType )
	{
	case FDIO:	/* File descriptor.				*/
		for ( cnt = 0, pBuffer = buffer; cnt != n; )
		{
			switch ( (nBytes = write( fd, (char *)pBuffer, n-cnt )) )
			{
			case 0:	/* EOF reached.				*/
				return ( cnt );
			case -1:/* Error.				*/
				BINERROR( BINESYS, -1 );
			default:
				pBuffer += nBytes;
				cnt     += nBytes;
				break;
			}
		}
		return ( cnt );

	case FPIO:	/* File pointer.				*/
		for ( cnt = 0, pBuffer = buffer; cnt != n; )
		{
			switch ( (nBytes = fwrite( (char *)pBuffer, 1, n-cnt, fp )) )
			{
			case 0:	/* EOF or error reached.		*/
				return ( cnt );
			default:
				pBuffer += nBytes;
				cnt     += nBytes;
				break;
			}
		}
		return ( cnt );

	case DATAIO:	/* Data buffer.					*/
		memcpy( (void*) data, (void*) buffer, n);
		return ( n );
	}
	return( 0 );
	/*NOTREACHED*/
}





/*
 *  FUNCTION
 *	binReadCharMBF	-  Read characters from an MBF input
 *	binReadCharLBF	-  Read characters from an LBF input
 *	binWriteCharMBF	-  Write characters to MBF output
 *	binWriteCharLBF	-  Write characters to LBF output
 *
 *  DESCRIPTION
 *	If the host and input/output data share the same size, then a
 *	simple byte-for-byte read or write is done.
 *
 *	Otherwise, for reads we read the required number of bytes from the
 *	input into a holding buffer, then pull out the least-significant
 *	byte of each 'nBytes' item and copy it into the next output buffer slot.
 *
 *	If the incomming data has more bits of precision (and uses them) than
 *	the host-side character, then truncation occurs and the user's
 *	integer truncation callback is called.  (if the input's type is signed,
 *	bytes that aren't 0x00 or 0xFF (sign-extension) indicate truncation.
 *	if the input's type is unsigned, only non-0x00 bytes indicate
 *	truncation).
 *
 *	For each item to be written, the byte is extracted from the input
 *	buffer and added to a holding buffer.  More-significant bytes in the
 *	holding buffer are zero padded or sign-extended.
 *
 *	For all four routines, a 'byteHold' buffer allocated on the stack
 *	is prefered.  However, if the buffer isn't big enough, a dynamically
 *	allocated holding buffer is used.
 */

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binReadCharMBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binReadCharMBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int            ioType;		/* Use buffered or unbuffered I/O*/
	int            fd;		/* File descriptor		*/
	FILE          *fp;		/* File pointer			*/
	unsigned char *data;		/* Input data			*/
	unsigned char *buf;		/* Data buffer			*/
	int            type;		/* Always char			*/
	int            nBytes;		/* # of bytes when in file	*/
	int            count;		/* # of items to read		*/
#endif
{
	unsigned char  byteHold[BINMAXBUF];	/* Input holding buffer	*/
	unsigned char  *pHold  = byteHold;/* Holding buffer pointer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated hold buf*/
	int		i, j;		/* Counters			*/
	unsigned char	thisOne, that;	/* Byte values to check for	*/


	if ( nBytes == 1 )		/* sizeof( char ) assumed to be 1*/
		return ( binByteRead( ioType, fd, fp, data, buf, nBytes*count));

	if ( (nBytes * count > BINMAXBUF) &&
		( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
		BINERROR( BINEMALLOC, -1 );
	if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}


	/*
	 *  Copy selected bytes from the input temp buffer to the return
	 *  buffer.  Check the bytes skipped to see if any of them contained
	 *  information that we're truncating.  If so, call the truncation
	 *  callback.
	 */
	thisOne = that = 0x00;
	if ( binTypeSigned[type] )
		that = 0xFF;
	for ( i = count; i; --i )
	{
		for ( j = nBytes - 1; j; --j, ++pHold )
		{
			if ( *pHold != thisOne && *pHold != that )
			{
				(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
					(pHold-(nBytes-j-1)), nBytes*8, 8 );
				pHold += j;
				break;
			}
		}
		*buf++ = *pHold++;	/* Use the last byte read in	*/
	}
	if ( pAlloc )
		free( (char *)pAlloc );
	return ( nBytes * count );
}

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binReadCharLBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binReadCharLBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int            ioType;		/* Use buffered or unbuffered I/O*/
	int            fd;		/* File descriptor		*/
	FILE          *fp;		/* File pointer			*/
	unsigned char *data;		/* Input data			*/
	unsigned char *buf;		/* Data buffer			*/
	int            type;		/* Always char			*/
	int            nBytes;		/* # of bytes when in file	*/
	int            count;		/* # of items to read		*/
#endif
{
	unsigned char  byteHold[BINMAXBUF];	/* Input holding buffer	*/
	unsigned char  *pHold  = byteHold;/* Holding buffer pointer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated hold buf*/
	int		i, j;		/* Counters			*/
	unsigned char	thisOne, that;	/* Byte values to check for	*/


	if ( nBytes == 1 )		/* sizeof( char ) assumed to be 1*/
		return ( binByteRead( ioType, fd, fp, data, buf, nBytes*count));

	if ( (nBytes * count > BINMAXBUF) &&
		( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
		BINERROR( BINEMALLOC, -1 );
	if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}


	/*
	 *  Copy selected bytes from the input temp buffer to the return
	 *  buffer.  Check the bytes skipped to see if any of them contained
	 *  information that we're truncating.  If so, call the truncation
	 *  callback.
	 */
	thisOne = that = 0x00;
	if ( binTypeSigned[type] )
		that = 0xFF;
	for ( i = count; i; --i )
	{
		*buf++ = *pHold++;	/* Use the first byte read in	*/
		for ( j = nBytes - 1; j; --j, ++pHold )
		{
			if ( *pHold != thisOne && *pHold != that )
			{
				(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
					(pHold-(nBytes-j)), nBytes*8, 8 );
				pHold += j;
				break;
			}
		}
	}
	if ( pAlloc )
		free( (char *)pAlloc );
	return ( nBytes * count );
}

static int				/* Returns # of bytes write	*/
#ifdef __STDC__
binWriteCharMBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binWriteCharMBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Output data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Always char			*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to write		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Temp holding buffer	*/
	unsigned char  *pHold  = byteHold;/* Pointer to holding buffer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated hold buf*/


	if ( nBytes == 1 )		/* sizeof( char ) assumed to be 1*/
		return ( binByteWrite( ioType, fd, fp, data, buf, count ) );

	if ( (nBytes * count > BINMAXBUF) &&
		( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
		BINERROR( BINEMALLOC, -1 );


	/*
	 *  Transfer the input data to the holding buffer in the right
	 *  units.  Zero pad or sign-extend as necessary.
	 */
	memset( (void *)pHold, 0x00, nBytes * count);
	if ( binTypeSigned[type] )
		for ( i = 0; i < count; i++, *pHold++ = *buf++ )
			if ( (*buf & 0x70) != 0 )	/* sign bit set	*/
				for ( j = 1; j < nBytes; j++ )
					*pHold++ = 0xFF;/* Sign extend	*/
			else
				pHold += nBytes - 1;
	else
		for ( i = 0; i < count; i++, *pHold++ = *buf++ )
			pHold += nBytes - 1;


	/*
	 *  Write the hold buffer to the output.
	 */
	if ( pAlloc )
	{
		i = binByteWrite( ioType, fd, fp, data, pAlloc, nBytes * count );
		free( (char *)pAlloc );
	}
	else
		i = binByteWrite( ioType, fd, fp, data, byteHold, nBytes * count );
	return ( i );
}

static int				/* Returns # of bytes write	*/
#ifdef __STDC__
binWriteCharLBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binWriteCharLBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Output data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Always char			*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to write		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Temp holding buffer	*/
	unsigned char  *pHold  = byteHold;/* Pointer to holding buffer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated hold buf*/


	if ( nBytes == 1 )		/* sizeof( char ) assumed to be 1*/
		return ( binByteWrite( ioType, fd, fp, data, buf, count ) );

	if ( (nBytes * count > BINMAXBUF) &&
		( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
		BINERROR( BINEMALLOC, -1 );


	/*
	 *  Transfer the input data to the holding buffer in the right
	 *  units.  Sign-extend as necessary.
	 */
	memset( (void *)pHold, 0x00, nBytes * count);
	if ( binTypeSigned[type] )
		for ( i = 0; i < count; i++ )
		{
			*pHold++ = *buf;
			if ( (*buf++ & 0x70) != 0 )	/* sign bit set	*/
				for ( j = 1; j < nBytes; j++ )
					*pHold++ = 0xFF;/* Sign extend	*/
			else
				pHold += nBytes - 1;
		}
	else
		for ( i = 0; i < count; i++, pHold += nBytes )
			*pHold = *buf++;


	/*
	 *  Write the hold buffer to the output.
	 */
	if ( pAlloc )
	{
		i = binByteWrite( ioType, fd, fp, data, pAlloc, nBytes * count );
		free( (char *)pAlloc );
	}
	else
		i = binByteWrite( ioType, fd, fp, data, byteHold, nBytes * count );
	return ( i );
}





/*
 *  FUNCTION
 *	binReadIntMBF	-  Read MBF input into integers
 *	binReadIntLBF	-  Read LBF input into integers
 *	binWriteIntMBF	-  Write from integers to MBF output
 *	binWriteIntLBF	-  Write from integers to LBF output
 *
 *  DESCRIPTION
 *	These functions read or write integers from or to MBF or LBF files.
 *	The basic shell of all four routines is identical.
 *
 *	If the host's size of the item to be read or written is the same
 *	as the size in the file, and the byte order is the same, then
 *	all four routines default to using the read() or write() system
 *	call directly on the incomming buffer of data.
 *
 *	Otherwise the packing of data differs between the host and the file
 *	and data must be copied to/from the byte array sent to the read()
 *	and write() system calls.
 *
 *	The incomming buffer of data must be truncated or sign-extended as
 *	it is copied into the outgoing byte array.  Code differs slightly
 *	between LBF and MBF hosts.
 *
 *	All four of these functions depend upon the binTypeSize,
 *	binTypeRes, and binTypeSigned arrays for information on the type
 *	to be read or written:
 *
 *		binTypeSize	size of item, as stored by the host
 *		binTypeRes	resolution of item (# of significant bytes)
 *		binTypeSigned	signed type?
 *
 *	On most machines, binTypeSize and binTypeRes are identical.
 *	The CRAY 'short' is an example of when they are not.  A CRAY
 *	'short' is stored in 8 bytes, but only the lower 3 bytes can
 *	be used.  In this case, binTypeSize[SHORT] = 8, but
 *	binTypeRes[SHORT] = 3.
 *
 *	We could use a great many more #ifdef's to remove lines like:
 *		buf += size - res;
 *	which is a waste of time when size and res are the same for a
 *	machine.  However, adding #ifdef's makes getting the code
 *	working on a new machine more difficult, and creates a maintenance
 *	headache.  The computation cost of such extra statements is
 *	low compared to the cost of the other byte-swapping loops so
 *	the execution time savings doesn't seem worth the increase in
 *	maintenance effort.
 */

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binReadIntMBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binReadIntMBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Input data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to read			*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to read		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold = byteHold;/* Byte holder			*/
	int             res;		/* Resolution of type		*/
	int             size;		/* Size of type			*/
	int             issigned;	/* Is type signed?		*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	unsigned char   thisOne, that;	/* Byte comparison holders	*/


	size     = binTypeSize[type];	/* Storage size of item		*/
	res      = binTypeRes[type];	/* Significant bytes of item	*/
	issigned = binTypeSigned[type];	/* Whether signed or not	*/


	if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
		return ( binByteRead( ioType, fd, fp, data, buf, nBytes * count ));

	if ( (nBytes * count > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL))
		BINERROR( BINEMALLOC, -1 );
	if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}


	/*
	 *  Copy data from the holding buffer into the return buffer.
	 */
	if ( nBytes < res )
	{
		/*
		 *  Holding buffer items require fewer bytes than the
		 *  destination.  We've got to sign-extend signed incomming
		 *  data as we copy it to the destination.
		 */
		memset( (void *)buf, 0x00, size * count);
		for ( i = 0; i < count; i++ )
		{
#ifdef MBF				/* MBF host			*/
			buf += size - res;
			if ( issigned && (*pHold & 0x80) )
				for ( j = res - nBytes; j; j-- )
					*buf++ = 0xFF;	/* Sign extend	*/
			else
				buf += res - nBytes;
			for ( j = 0; j < nBytes; j++ )
				*buf++ = *pHold++;

#else					/* LBF host			*/
			for ( j = nBytes - 1; j >= 0; j-- )
				buf[j] = *pHold++;
			if ( issigned && (*pHold & 0x80) )
			{
				buf += nBytes;
				for ( j = res - nBytes; j; j-- )
					*buf++ = 0xFF;	/* Sign extend	*/
				buf += size - res;
			}
			else
				buf += size;
#endif
		}
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( nBytes * count );
	}


	/*
	 *  Holding buffer items require the same number, or more bytes
	 *  than the destination.  We've got to truncate incomming data
	 *  as we copy it to the destination.
	 */
	thisOne = that = 0x00;
	if ( binTypeSigned[type] )
		that = 0xFF;

	for ( i = 0; i < count; i++ )
	{
		for ( j = 0; j < nBytes - res; j++, pHold++ )
		{
			if ( *pHold != thisOne && *pHold != that )
			{
				(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
					(pHold-j), nBytes*8, res*8 );
				pHold += nBytes-res-j;
				break;
			}
		}
#ifdef MBF				/* MBF host			*/
		buf += size - res;
		for ( j = res; j; j-- )
			*buf++ = *pHold++;
#else					/* LBF host			*/
		for ( j = res - 1; j >= 0; j-- )
			buf[j] = *pHold++;
		buf += size;
#endif
	}
	if ( pAlloc )
		free( (char *)pAlloc );
	return ( nBytes * count );
}

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binReadIntLBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binReadIntLBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Input data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to read			*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to read		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold = byteHold;/* Byte holder			*/
	int             res;		/* Resolution of type		*/
	int             size;		/* Size of type			*/
	int             issigned;	/* Is type signed?		*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	unsigned char   thisOne, that;	/* Byte comparison holders	*/


	size     = binTypeSize[type];	/* Storage size of item		*/
	res      = binTypeRes[type];	/* Significant bytes of item	*/
	issigned = binTypeSigned[type];	/* Whether signed or not	*/


	if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
		return ( binByteRead( ioType, fd, fp, data, buf, nBytes * count ));

	if ( (nBytes * count > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL))
		BINERROR( BINEMALLOC, -1 );
	if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}


	/*
	 *  Copy data from the holding buffer into the return buffer.
	 */
	if ( nBytes < res )
	{
		/*
		 *  Holding buffer items require fewer bytes than the
		 *  destination.  We've got to sign-extend signed incomming
		 *  data as we copy it to the destination.
		 */
		memset( (void *)buf, 0x00, size * count);
		for ( i = 0; i < count; i++ )
		{
#ifdef MBF				/* MBF host			*/
			buf += size - res;
			if ( issigned && (*pHold & 0x80) )
				for ( j = res - nBytes; j; j-- )
					*buf++ = 0xFF;	/* Sign extend	*/
			else
				buf += res - nBytes;
			for ( j = nBytes - 1; j >= 0; j-- )
				buf[j] = *pHold++;
			buf += nBytes;
#else					/* LBF host			*/
			for ( j = nBytes; j; j-- )
				*buf++ = *pHold++;
			if ( issigned && (*(pHold-1) & 0x80) )
				for ( j = res - nBytes; j; j-- )
					*buf++ = 0xFF;	/* Sign extend	*/
			else
				buf += res - nBytes;
			buf += size - res;
#endif
		}
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( nBytes * count );
	}

	/*
	 *  Holding buffer items require the same number, or more bytes
	 *  than the destination.  We've got to truncate incomming data
	 *  as we copy it to the destination.
	 */
	thisOne = that = 0x00;
	if ( binTypeSigned[type] )
		that = 0xFF;

	for ( i = 0; i < count; i++ )
	{
#ifdef MBF				/* MBF host			*/
		buf += size - res;
		for ( j = res - 1; j >= 0; j-- )
			buf[j] = *pHold++;
		buf += res;
#else					/* LBF host			*/
		for ( j = res; j; j-- )
			*buf++ = *pHold++;
		buf += size - res;
#endif
		for ( j = 0; j < nBytes - res; j++, pHold++ )
		{
			if ( *pHold != thisOne && *pHold != that )
			{
				(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
					(pHold-j-res), nBytes*8, res*8 );
				pHold += nBytes-res-j;
				break;
			}
		}
	}
	if ( pAlloc )
		free( (char *)pAlloc );
	return ( nBytes * count );
}

static int				/* Returns # of bytes written	*/
#ifdef __STDC__
binWriteIntMBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binWriteIntMBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Output data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to write		*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to write		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold = byteHold;/* Data buffer pointer		*/
	int             res;		/* Resolution of type		*/
	int             size;		/* Size of type			*/
	int             issigned;	/* Is type signed?		*/
	int             n;		/* # of bytes written		*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	unsigned char	thisOne, that;	/* Byte comparison holders	*/

	size     = binTypeSize[type];	/* Storage size of item		*/
	res      = binTypeRes[type];	/* Significant bytes of item	*/
	issigned = binTypeSigned[type];	/* Whether signed or not	*/
	n        = nBytes * count;


	if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
		return ( binByteWrite( ioType, fd, fp, data, buf, n ));

	if ( (nBytes * count > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
		BINERROR( BINEMALLOC, -1 );

	if ( nBytes <= res )
	{
		/*
		 *  Writing same or fewer bytes than stored by host.
		 *  Truncate high-order bytes.
		 */
		thisOne = that = 0x00;
		if ( binTypeSigned[type] )
			that = 0xFF;

		for ( i = 0; i < count; i++ )
		{
#ifdef MBF				/* MBF host			*/
			for ( j = 0; j < size - nBytes; j++, buf++ )
			{
				if ( *buf != thisOne && *buf != that )
				{
					(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
						(buf-j), res*8, nBytes*8 );
					buf += size - nBytes - j;
					break;
				}
			}
			for ( j = nBytes; j; j-- )
				*pHold++ = *buf++;
#else					/* LBF host			*/
			for ( j = nBytes - 1; j >= 0; j-- )
				pHold[j] = *buf++;
			pHold += nBytes;

			for ( j = 0; j < size - nBytes; j++, buf++ )
			{
				if ( *buf != thisOne && *buf != that )
				{
					(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
						(buf-j-nBytes), res*8, nBytes*8 );
					buf += size - nBytes - j;
					break;
				}
			}
#endif
		}
		if ( pAlloc )
		{
			i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
			free( (char *)pAlloc );
		}
		else
			i = binByteWrite( ioType, fd, fp, data, byteHold, n );
		return ( i );
	}

	/*
	 *  Writing more bytes than stored by host.  Need to sign extend
	 *  or pad with 0's.
	 */
	memset( (void *)pHold, 0x00, n);
	for ( i = 0; i < count; i++ )
	{
#ifdef MBF				/* MBF host			*/
		if ( issigned && (*buf & 0x80) )
			for ( j = nBytes - res; j; j-- )
				*pHold++ = 0xFF;	/* Sign extend	*/
		else
			pHold += nBytes - res;
		buf += size - res;
		for ( j = res; j; j-- )
			*pHold++ = *buf++;
#else					/* LBF host			*/
		if ( issigned && (buf[res-1] & 0x80) )
			for ( j = nBytes - res; j; j-- )
				*pHold++ = 0xFF;	/* Sign extend	*/
		else
			pHold += nBytes - res;
		for ( j = res - 1; j >= 0; j-- )
			pHold[j] = *buf++;
		buf   += size - res;
		pHold += res;
#endif
	}

	if ( pAlloc )
	{
		i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
		free( (char *)pAlloc );
	}
	else
		i = binByteWrite( ioType, fd, fp, data, byteHold, n );
	return ( i );
}

static int				/* Returns # of bytes written	*/
#ifdef __STDC__
binWriteIntLBF( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binWriteIntLBF( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Output data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to write		*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to write		*/
#endif
{
	int             i, j;		/* Counters			*/
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold = byteHold;/* Data buffer pointer		*/
	int             res;		/* Resolution of type		*/
	int             size;		/* Size of type			*/
	int             issigned;	/* Is type signed?		*/
	int             n;		/* # of bytes written		*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	unsigned char	thisOne, that;	/* Byte comparison holders	*/


	size     = binTypeSize[type];	/* Storage size of item		*/
	res      = binTypeRes[type];	/* Significant bytes of item	*/
	issigned = binTypeSigned[type];	/* Whether signed or not	*/
	n        = nBytes * count;


	if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
		return ( binByteWrite( ioType, fd, fp, data, buf, n ));

	if ( (nBytes * count > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
		BINERROR( BINEMALLOC, -1 );


	if ( nBytes <= res )
	{
		/*
		 *  Writing same or fewer bytes than stored by host.
		 *  Truncate high-order bytes.
		 */
		thisOne = that = 0x00;
		if ( binTypeSigned[type] )
			that = 0xFF;

		for ( i = 0; i < count; i++ )
		{
#ifdef MBF				/* MBF host			*/
			for ( j = 0; j < size - nBytes; j++, buf++ )
			{
				if ( *buf != thisOne && *buf != that )
				{
					(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
						(buf-j), res*8, nBytes*8 );
					buf += size - nBytes - j;
					break;
				}
			}
			for ( j = nBytes - 1; j >= 0; j-- )
				pHold[j] = *buf++;
			pHold += nBytes;
#else					/* LBF host			*/
			for ( j = nBytes; j; j-- )
				*pHold++ = *buf++;
			for ( j = 0; j < size - nBytes; j++, buf++ )
			{
				if ( *buf != thisOne && *buf != that )
				{
					(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
						(buf-j-nBytes), res*8, nBytes*8 );
					buf += size - nBytes - j;
					break;
				}
			}
#endif
		}
		if ( pAlloc )
		{
			i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
			free( (char *)pAlloc );
		}
		else
			i = binByteWrite( ioType, fd, fp, data, byteHold, n );
		return ( i );
	}

	/*
	 *  Writing more bytes than stored by host.  Need to sign extend
	 *  or pad with 0's.
	 */
	memset( (void *)pHold, 0x00, n);
	for ( i = 0; i < count; i++ )
	{
#ifdef MBF				/* MBF host			*/
		buf += size - res;
		for ( j = res - 1; j >= 0; j-- )
			pHold[j] = *buf++;
		pHold += res;
		if ( issigned && (*buf & 0x80) )
			for ( j = nBytes - res; j; j-- )
				*pHold++ = 0xFF;	/* Sign extend	*/
		else
			pHold += nBytes - res;
#else					/* LBF host			*/
		for ( j = res; j; j-- )
			*pHold++ = *buf++;
		if ( issigned && (*(buf-1) & 0x80) )
			for ( j = nBytes - res; j; j-- )
				*pHold++ = 0xFF;	/* Sign extend	*/
		else
			pHold += nBytes - res;
		buf += size - res;
#endif
	}

	if ( pAlloc )
	{
		i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
		free( (char *)pAlloc );
	}
	else
		i = binByteWrite( ioType, fd, fp, data, byteHold, n );
	return ( i );
}





/*
 *  FUNCTION
 *	binReadFloat	-  Read float from a input
 *	binWriteFloat	-  Write from float to output
 *
 *  DESCRIPTION
 *	If the host and file floating point formats, sizes of those formats,
 *	and byte orders are the same, then a simple read or writesystem call
 *	is used.
 *
 *	Otherwise, for reads, file data is read in to a holding array and
 *	passed off to binConvertFloat(), one at a time.
 *
 *	For writes, host data is passed to binConvertFloat() to conver into
 *	a holding array, and then written to the file.
 *
 *	NOTE:  This code could be sped up by including binConvertFloat()
 *	code in-line and having different code for different file byte orders.
 *	However, in the interests of reducing the maintenance hassle for the
 *	rather complex code in binConvertFloat(), this has not been done.
 */

static int				/* Returns # of bytes read	*/
#ifdef __STDC__
binReadFloat( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binReadFloat( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Input data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to read			*/
	int             nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to read		*/
#endif
{
	int             i;		/* Counter			*/
	binFloatFormatCooked *host;	/* Host's float format info	*/
	binFloatFormatCooked *file;	/* File's float format info	*/
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold  = byteHold;/* Data buffer pointer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	int             size;		/* Size of host type		*/
	int		n;		/* # of bytes read		*/


	size = binTypeSize[type];
	host = binHostFloatFormat;
	do
	{
		if ( host->bin_nbytes == size && host->bin_format.bin_subname )
			break;
	} while ( (++host)->bin_format.bin_number == BINHOSTFLOAT );
	if ( host->bin_format.bin_number != BINHOSTFLOAT )
		BINERROR( BINEFLOATUNSUPPORTED, -1 );
	file = binFileFloatFormat;
	i    = file->bin_format.bin_number;
	do
	{
		if ( file->bin_nbytes == nBytes && file->bin_format.bin_subname)
			break;
	} while ( (++file)->bin_format.bin_number == i );
	if ( file->bin_format.bin_number != i )
		BINERROR( BINEFLOATUNSUPPORTED, -1 );
	n = nBytes * count;


	if ( host == file && size == nBytes && binFileBO == BINHOSTBO )
		return ( binByteRead( ioType, fd, fp, data, buf, n ) );

	if ( (n > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
		BINERROR( BINEMALLOC, -1 );
	if ( binByteRead( ioType, fd, fp, data, pHold, n ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}

	/* Convert from file format to host format.			*/
	if ( binConvertFloat( fd, file, binFileBO, nBytes, pHold,
		host, BINHOSTBO, size, buf, count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}

	if ( pAlloc )
		free( (char *)pAlloc );

	return ( n );
}

static int				/* Returns # of bytes written	*/
#ifdef __STDC__
binWriteFloat( int ioType, int fd, FILE *fp, unsigned char *data,
	unsigned char *buf, int type, int nBytes, int count )
#else
binWriteFloat( ioType, fd, fp, data, buf, type, nBytes, count )
	int             ioType;		/* Use buffered or unbuffered I/O*/
	int             fd;		/* File descriptor		*/
	FILE           *fp;		/* File pointer			*/
	unsigned char  *data;		/* Output data			*/
	unsigned char  *buf;		/* Data buffer			*/
	int             type;		/* Type to write		*/
	int		nBytes;		/* # of bytes when in file	*/
	int             count;		/* # of items to write		*/
#endif
{
	unsigned char   byteHold[BINMAXBUF];	/* Byte buffer		*/
	unsigned char  *pHold  = byteHold;/* Data buffer pointer	*/
	unsigned char  *pAlloc = NULL;	/* Dynamically allocated buffer	*/
	binFloatFormatCooked *host;	/* Host's float format info	*/
	binFloatFormatCooked *file;	/* File's float format info	*/
	int             size;		/* Size of type			*/
	int             n;		/* # of bytes read		*/
	int		i;		/* Tmp				*/


	size = binTypeSize[type];
	host = binHostFloatFormat;
	do
	{
		if ( host->bin_nbytes == size && host->bin_format.bin_subname )
			break;
	} while ( (++host)->bin_format.bin_number == BINHOSTFLOAT );
	if ( host->bin_format.bin_number != BINHOSTFLOAT )
		BINERROR( BINEFLOATUNSUPPORTED, -1 );
	file = binFileFloatFormat;
	i    = file->bin_format.bin_number;
	do
	{
		if ( file->bin_nbytes == nBytes && file->bin_format.bin_subname)
			break;
	} while ( (++file)->bin_format.bin_number == i );
	if ( file->bin_format.bin_number != i )
		BINERROR( BINEFLOATUNSUPPORTED, -1 );
	n = nBytes * count;


	if ( host == file && size == nBytes && binFileBO == BINHOSTBO )
		return ( binByteWrite( ioType, fd, fp, data, buf, n ) );

	if ( (n > BINMAXBUF) &&
		((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
		BINERROR( BINEMALLOC, -1 );


	/* Convert from host format to file format.			*/
	if ( binConvertFloat( fd, host, BINHOSTBO, size, buf,
		file, binFileBO, nBytes, pHold, count ) == -1 )
	{
		if ( pAlloc )
			free( (char *)pAlloc );
		return ( -1 );
	}

	/* Write out the converted data.				*/
	n = binByteWrite( ioType, fd, fp, data, pHold, n );
	if ( pAlloc )
		free( (char *)pAlloc );
	return ( n );
}






/*
 *  FUNCTION
 *	binConvertFloat	-  convert a float from one format to another
 *
 *  DESCRIPTION
 *	This routine does the actual conversion of data in one floating
 *	point format into another.  It handles differences in sizes of
 *	the exponent and mantissa fields, underflow and overflow conditions,
 *	exponent biasing, and whether or not the redundant most-significant
 *	bit in the mantissa is saved in the format.
 *
 *	The procedure is thus...
 *
 *	1.  Extract out the sign-bit from the source.  It is assumed here
 *	    that the sign-bit is the most-significant bit in the most-
 *	    significant byte of the source data.
 *
 *	2.  Extract out the exponent bits from the source.  The exponent
 *	    is built up into an UNSIGNED 32-BIT INT by shifting and masking.
 *	    It is assumed that the exponent will fit into a 32-bit integer,
 *	    and that the host actually supports such a thing.  The exponent
 *	    is then converted to a SIGNED 32-BIT INT and unbiased.  It is
 *	    assumed that the unbiased exponent will fit into a 32-bit int.
 *
 *	3.  Conditions for extraction of the mantissa from the source are
 *	    figured out.  Primarily this involves checking if the source
 *	    and destination formats both treat the redundant most-significant
 *	    mantissa bit (the "implied bit") the same way.  If they don't,
 *	    then changes in the way the mantissa is copied in to the destination
 *	    must be figured out.  Along the way the signed exponent may be
 *	    altered by adding or subtracting one due to the implied bit's
 *	    existance or non-existance.
 *
 *	4.  The exponent is checked for underflow and overflow.  On underflow
 *	    the destination float is set to 0 and we return.  On overflow,
 *	    the sign and exponent fields are set to the values appropriate
 *	    for the destination format and the mantissa is not copied, thus
 *	    leaving it zero.  If all is OK, the exponent is biased by the
 *	    desination bias.
 *
 *	5.  The mantissa is then copied.  This is non-trivial because the
 *	    source and desination formats may have different numbers of
 *	    bits in the mantissa, and may start the mantissa at different
 *	    bit positions in the most-significant mantissa byte.  So, what
 *	    we have here is a non-aligned bit-copy operation.
 *
 *	    To make this easier (and faster?), the source data is copied,
 *	    one byte at a time, in to a temporary ALIGNED byte array.
 *	    During the copy process the implied bit is set or not-set if
 *	    needed.
 *
 *	    The temp byte array data is then copied in to the destination
 *	    byte array, with further shifting and masking taking place to
 *	    align it appropriately for the destination format.
 *
 *	6.  The exponent is then copied in to the destination and the sign
 *	    bit set if the source was negative.
 *
 *	NOTE:  This code is NOT FAST!  Sorry.  The object was to write a
 *	generic floating point format converter that didn't have to change
 *	for different formats and different source and destination byte
 *	orders.  This code could be sped up most easily by duplicating
 *	this routine four times, one for each combination of source and
 *	destination byte orders, then removing the unnecessary byte order
 *	if's.  This has not been done initially because of the increase in
 *	the maintenance hassle of the code.
 *
 *	Other speed-ups that could be done include:
 *		1.  Watching for the case where the source and desination
 *		    formats are the same, but the byte order differs and
 *		    then just do a byte swaped copy.
 *
 *		2.  If the mantissa will fit into an int (whatever the size
 *		    is on the host), copy it in to an int via shift's and
 *		    masks, then copy it back out into the desination.  This
 *		    would save all the byte copy hassle for single-precision
 *		    floats.
 */

#define MAXTMP		400		/* Max # of bytes in temps	*/
#define MAXMANT		100		/* Max # of bytes in temp mantissa*/

static int				/* Returns status		*/
#ifdef __STDC__
binConvertFloat( int fd, binFloatFormatCooked *srcfmt, int srcbo, int nsrcbytes,
	unsigned char *srcbytes, binFloatFormatCooked *dstfmt, int dstbo,
	int ndstbytes, unsigned char *dstbytes, int count )
#else
binConvertFloat( fd, srcfmt, srcbo, nsrcbytes, srcbytes,
		     dstfmt, dstbo, ndstbytes, dstbytes, count )
	int		fd;		/* File descriptor (for error handler)*/
	binFloatFormatCooked *srcfmt;	/* Source's float format info	*/
	int             srcbo;		/* Source's byte order		*/
	int             nsrcbytes;	/* # of bytes when in src	*/
	unsigned char  *srcbytes;	/* Source data			*/
	binFloatFormatCooked *dstfmt;	/* Desintation's float format info*/
	int             dstbo;		/* Destination's byte order	*/
	int		ndstbytes;	/* # of bytes when in dst	*/
	unsigned char  *dstbytes;	/* Destination data		*/
	int		count;		/* Number of conversions to do	*/
#endif
{
	int             i, j, k;	/* Counters and temps		*/
	int		n;		/* Count of things		*/

	int             negative;	/* Negative float?		*/
	unsigned int    exponent;	/* Exponent			*/
	int             signed_exponent;/* Unbiased signed exponent	*/
	unsigned char	implied_bit;	/* Implied bit of mantissa	*/

	unsigned char  *src;		/* Source bytes pointer		*/
	unsigned char  *dst;		/* Destination bytes pointer	*/
	unsigned char  *tmp;		/* Temporary uchar pointer	*/
	unsigned char	tmpmant[MAXMANT];/* Temporary mantissa array	*/
	unsigned char	tmpsrc[MAXTMP];/* Temporary src float bytes array*/
	unsigned char	tmpdst[MAXTMP];/* Temporary src float bytes array*/
	unsigned char  *allocsrc;	/* Allocated tmpsrc pointer	*/
	unsigned char  *allocdst;	/* Allocated tmpdst pointer	*/

	int		start_byte;	/* Starting byte of mantissa	*/
	unsigned char	mask1;		/* First mantissa byte mask	*/
	unsigned char	mask2;		/* Second mantissa byte mask	*/
	unsigned char	byte1_mask;	/* Special mask for 1st src byte*/
	int		shift;		/* Amount to shift mantissa bytes*/
	int		shift8;		/* 8 - shift			*/


	src      = srcbytes;
	dst      = dstbytes;
	allocsrc = NULL;
	allocdst = NULL;


	/*
	 *  Check the source format's flags to see if there is any special
	 *  pre-processing of the source bytes that needs to be done.
	 */
	if ( srcfmt->bin_format.bin_flags & BINVAXBO )
	{
		/*
		 *  Source float uses the VAX's LBF/MBF mix byte ordering.
		 *  Floating point values are ordered as a list of 16-bit
		 *  quantities, from most-significant to least-significant.
		 *  Within a 16-bit quantity, the first byte is the least-
		 *  significant and the second the most-significant.
		 *
		 *  For example, a single precision float ('f' format)
		 *  is a 4-byte quantity:
		 *
		 *	        7      0
		 *	byte 0  EMMMMMMM    high mantissa bits
		 *	byte 1  SEEEEEEE
		 *	byte 2  MMMMMMMM    low mantissa bits
		 *	byte 3  MMMMMMMM    middle mantissa bits
		 *
		 *  To handle VAX byte ordering of floats, we copy the source
		 *  bytes in to a temporary byte array, swapping every two
		 *  bytes, then set the source byte order to the opposite of
		 *  that selected.  The generic conversion algorithm below
		 *  can handle it from there.
		 */
		src = tmpsrc;
		n   = nsrcbytes * count;
		if ( ( n > MAXTMP ) &&
			((src = allocsrc = (unsigned char *)malloc( (unsigned int)n )) == NULL ) )
			BINERROR( BINEMALLOC, -1 );

		n /= 2;
		tmp = srcbytes;
		do
		{
			*src++  = tmp[1];
			*src++  = tmp[0];
			tmp    += 2;
		} while ( --n );
		src = tmpsrc;
		if ( allocsrc )
			src = allocsrc;
		srcbo = (srcbo == BINLBF) ? BINMBF : BINLBF;
	}


	/*
	 *  Check the destination format's flags to see if there is any special
	 *  post-processing of the destination bytes that needs to be setup.
	 */
	if ( dstfmt->bin_format.bin_flags & BINVAXBO )
	{
		/*
		 *  Destination float uses the VAX's LBF/MBF mix byte ordering.
		 *  See the comment above for details.
		 *
		 *  To handle VAX byte ordering of floats, we set the
		 *  destination pointer to point to a temp array and set the
		 *  destination byte order to the opposite of that selected.
		 *  When we've completed the conversion, we'll copy from
		 *  the temp array in to the real destination, doing byte
		 *  swapping along the way.
		 */
		dst = tmpdst;
		n   = ndstbytes * count;
		if ( ( n > MAXTMP ) &&
			( (dst = allocdst = (unsigned char *)malloc( (unsigned int)n )) == NULL ) )
			BINERROR( BINEMALLOC, -1 );
		dstbo = (dstbo == BINLBF) ? BINMBF : BINLBF;
	}


	/*
	 *  Zero out the dst float as a starting point.
	 */
	memset( (void *)dst, 0x00, ndstbytes * count);


	/*
	 *  Loop through the conversions to do.
	 */
	n = count;
	do
	{
		/*
		 *  Check the sign bit.
		 *	Assume sign bit is high bit in most-significant byte.
		 */
		if ( srcbo == BINMBF )
		{
			if ( (src[0] & 0x80) == 0 )
				negative = FALSE;
			else
				negative = TRUE;
		}
		else
		{
			if ( (src[nsrcbytes-1] & 0x80) == 0 )
				negative = FALSE;
			else
				negative = TRUE;
		}

		/*
		 *  Extract and unbias the exponent.
		 *	Assume won't overflow unsigned int.
		 */
		if ( srcbo == BINMBF )
		{
			i = nsrcbytes - 1 - srcfmt->bin_expStartByte;
			k = nsrcbytes - 1 - srcfmt->bin_expEndByte;
			exponent = src[i--] >> srcfmt->bin_expShift;
			for ( j = (8-srcfmt->bin_expShift); i > k; j += 8 )
				exponent |= ((unsigned int)src[i--]) << j;
			exponent |= ((unsigned int)src[i] & srcfmt->bin_expEndMask) <<j;
		}
		else
		{
			i = srcfmt->bin_expStartByte;
			k = srcfmt->bin_expEndByte;
			exponent = src[i++] >> srcfmt->bin_expShift;
			for ( j = (8-srcfmt->bin_expShift); i < k; j += 8 )
				exponent |= ((unsigned int)src[i++]) << j;
			exponent |= ((unsigned int)src[i] & srcfmt->bin_expEndMask) <<j;
		}
		if ( exponent == 0 )
		{
			/*
			 *  Original float's biased exponent was zero.
			 *  By definition, regardless of implied bit handling
			 *  or exponent biasing, this is a zero float.  Leave
			 *  the dst float all zeros.
			 */
			src += nsrcbytes;
			dst += ndstbytes;
			continue;
		}
		signed_exponent = exponent - srcfmt->bin_format.bin_expBias;

		/*
		 *  Set up for copying the mantissa into the temporary array.
		 */
		shift = srcfmt->bin_expShift;
		if ( srcfmt->bin_format.bin_mantImplied != dstfmt->bin_format.bin_mantImplied )
		{
			/*
			 *  Dest and src formats don't both handle the implied
			 *  bit the same.
			 *
			 *  If the src format has one, but the dst doesn't,
			 *  remove the bit during the copy and subtract one
			 *  from the exponent.
			 *
			 *  If the dst format has one, but the src format
			 *  doesn't, add the bit during the copy and add one
			 *  to the exponent.
			 */
			if ( srcfmt->bin_format.bin_mantImplied )
			{
				/* Source has implied bit.  Drop for dst.*/
				if ( shift == 0 )
				{
					shift = 7;
					mask1 = 0x7F;
					mask2 = 0x80;
					start_byte = srcfmt->bin_expStartByte-1;
				}
				else
				{
					shift--;
					mask1 = (~srcfmt->bin_expStartMask) >>1;
					mask2 = ~mask1;
					start_byte  = srcfmt->bin_expStartByte;
				}
				implied_bit = 0;
				signed_exponent--;
				if ( shift != 0 )
					byte1_mask = mask1;
				else
					byte1_mask = mask2;
			}
			else
			{
				/* Destination has implied bit.  Add from src.*/
				if ( shift == 7 )
				{
					shift = 0;
					start_byte = srcfmt->bin_expStartByte+1;
					byte1_mask = 0x7F;
				}
				else
				{
					shift++;
					mask2 = srcfmt->bin_expStartMask<<1;
					mask1 = ~mask2;
					start_byte = srcfmt->bin_expStartByte;
					byte1_mask = ~srcfmt->bin_expStartMask;
				}
				implied_bit = 0x80;
				signed_exponent++;
			}
		}
		else
		{
			/*
			 *  The dst and src formats both treat the implied
			 *  bit the same.
			 */
			mask2 = srcfmt->bin_expStartMask;
			mask1 = ~mask2;
			start_byte = srcfmt->bin_expStartByte;
			implied_bit = 0;
			if ( shift != 0 )
				byte1_mask = mask1;
			else
				byte1_mask = mask2;
		}

		/*
		 *  Bias the exponent to the dst format and check for
		 *  overflow and underflow.
		 *	Assume won't overflow int32.
		 */
		signed_exponent += dstfmt->bin_format.bin_expBias;
		if ( signed_exponent < 0 )
		{
			/*
			 *  Underflow.  Float in src had an exponent too
			 *  small to represent in the dst's format.  Leave
			 *  the dst float all zero's.
			 */
			src += nsrcbytes;
			dst += ndstbytes;

			/*
			 *  Report the error
			 */
			(*binErrFunc)( fd, binOp, BINEFLOATUNDERFLOW,
				&srcbytes[(count-n)*nsrcbytes],
				srcfmt->bin_format.bin_expBits,
				dstfmt->bin_format.bin_expBits );
			continue;
		}

		exponent = signed_exponent;
		if ( (exponent & ~dstfmt->bin_expMask) != 0 )
		{
			/*
			 *  Overflow.  Float in src had an exponent too
			 *  large to represent in the dst's format.  Set
			 *  the dst float to its overflow exponent and
			 *  sign.  Leave the mantissa zeroes.
			 */
			exponent = dstfmt->bin_format.bin_expOverflow;
			negative = dstfmt->bin_format.bin_signOverflow;;

			/*
			 *  Report the error
			 */
			(*binErrFunc)( fd, binOp, BINEFLOATOVERFLOW,
				&srcbytes[(count-n)*nsrcbytes],
				srcfmt->bin_format.bin_expBits,
				dstfmt->bin_format.bin_expBits );
		}
		else
		{
			/*
			 *  Zero out temporary mantissa byte array.  This
			 *  handles the filling in of zeros for mantissa
			 *  bytes in the dst format that are not provided by
			 *  the src format.
			 */
			memset( (void *)tmpmant, 0x00, MAXMANT);


			/*
			 *  Copy the src format bytes into the temporary array.
			 *  Bytes in the array are "left-justified" to bring
			 *  the most significant mantissa bit (perhaps the
			 *  implied bit) in to the most significant bit of
			 *  the first byte, and so on down the line.
			 *
			 *  Note:  the temporary array is in MBF format
			 *  regardless of the source format byte order.
			 */
			tmp = tmpmant;
			if ( shift != 0 )
			{
				shift8 = 8 - shift;
				if ( srcbo == BINMBF )
				{
					k = nsrcbytes - 1;
					j = k - start_byte;
					*tmp++ = ((src[j]&byte1_mask)<<shift8) |
						 ((src[j+1]&mask2)>>shift)     |
						 implied_bit;
					for ( i = j+1; i < k; i++ )
						*tmp++ = ((src[i] & mask1)<<shift8) |
							  ((src[i+1] & mask2) >> shift);
					*tmp = (src[i] & mask1) << shift8;
				}
				else
				{
					*tmp++ = ((src[start_byte] & byte1_mask)<<shift8) |
						 ((src[start_byte-1] & mask2)>>shift)  |
						 implied_bit;
					for ( i = start_byte - 1; i > 0; i-- )
						*tmp++ = ((src[i] & mask1)<<shift8) |
							  ((src[i-1] & mask2) >> shift);
					*tmp = (src[0] & mask1) << shift8;
				}
			}
			else
			{
				if ( srcbo == BINMBF )
				{
					*tmp++ = (src[nsrcbytes-start_byte] & byte1_mask) | implied_bit;
					for ( i = nsrcbytes-start_byte+1; i < nsrcbytes; i++ )
						*tmp++ = src[i];
				}
				else
				{
					*tmp++ = (src[start_byte-1] & byte1_mask) | implied_bit;
					for ( i = start_byte - 2; i >= 0; i-- )
						*tmp++ = src[i];
				}
			}
			tmp = tmpmant;

			/*
			 *  Copy the temporary array into the dst's mantissa.
			 */
			shift = dstfmt->bin_expShift;
			if ( shift != 0 )
			{
				mask2 = dstfmt->bin_expStartMask;
				mask1 = ~mask2;
				shift8= 8 - shift;
				if ( dstbo == BINMBF )
				{
					j = ndstbytes - 1;
					for ( i = j - dstfmt->bin_expStartByte; i < j; i++)
					{
						dst[i]   |= (*tmp >> shift8)&mask1;
						dst[i+1] |= (*tmp++<< shift)&mask2;
					}
					dst[i] |= (*tmp >> shift8) & mask1;
				}
				else
				{
					for ( i = dstfmt->bin_expStartByte; i > 0; i-- )
					{
						dst[i]   |= (*tmp >> shift8)&mask1;
						dst[i-1] |= (*tmp++<< shift)&mask2;
					}
					dst[0] |= (*tmp >> shift8) & mask1;
				}
			}
			else
			{
				if ( dstbo == BINMBF )
					for ( i = ndstbytes-dstfmt->bin_expStartByte; i < ndstbytes; i++ )
						dst[i] = *tmp++;
				else
					for ( i = dstfmt->bin_expStartByte-1; i >= 0; i-- )
						dst[i] = *tmp++;
			}
		}


		/*
		 *  Build the exponent and add in the sign.
		 */
		if ( dstbo == BINMBF )
		{
			i = ndstbytes - 1 - dstfmt->bin_expStartByte;
			j = ndstbytes - 1 - dstfmt->bin_expEndByte;
			dst[i--] |= (exponent << dstfmt->bin_expShift) &
				dstfmt->bin_expStartMask;
			exponent >>= (8 - dstfmt->bin_expShift);
			while ( i >= j )
			{
				dst[i--] |= exponent & 0xFF;
				exponent >>= 8;
			}
			dst[0] &= dstfmt->bin_expEndMask;
			if ( negative )
				dst[0] |= 0x80;
		}
		else
		{
			i = dstfmt->bin_expStartByte;
			j = dstfmt->bin_expEndByte;
			dst[i++] |= (exponent << dstfmt->bin_expShift) &
				dstfmt->bin_expStartMask;
			exponent >>= (8 - dstfmt->bin_expShift);
			while ( i <= j )
			{
				dst[i++] = exponent & 0xFF;
				exponent >>= 8;
			}
			dst[i-1] &= dstfmt->bin_expEndMask;
			if ( negative )
				dst[ndstbytes-1] |= 0x80;
		}

		src += nsrcbytes;
		dst += ndstbytes;
	} while ( --n );


	/*
	 *  Check the destination format's flags to see if there is any special
	 *  post-processing of the destination bytes that needs to be done.
	 */
	if ( dstfmt->bin_format.bin_flags & BINVAXBO )
	{
		/*
		 *  Destination float uses the VAX's LBF/MBF mix byte ordering.
		 *
		 *  To handle VAX byte ordering of floats, we copy the temporary
		 *  destination bytes (set up at the top of this function)
		 *  in to the destination byte array, swapping every two
		 *  bytes.
		 */
		if ( allocdst )
		{
			dst = allocdst;
			i   = count * ndstbytes / 2;
			do
			{
				*dstbytes++ = dst[1];
				*dstbytes++ = dst[0];
				dst += 2;
			} while ( --i );
			free( (char *)allocdst );
		}
		else
		{
			dst = tmpdst;
			i   = count * ndstbytes / 2;
			do
			{
				*dstbytes++ = dst[1];
				*dstbytes++ = dst[0];
				dst += 2;
			} while ( --i );
		}
	}

	if ( allocsrc )
		free( (char *)allocsrc );

	return ( 0 );
}
