/*
 * PDCONV.C - routines to do conversions between data formats
 *
 * Source Version: 9.0
 * Software Release #92-0043
 *
 */

#include "cpyright.h"

#include "pdb.h"

#include "pdform.h"

#define SHORT    0
#define INTEGER  1
#define LONG     2
#define FLOAT    3
#define DOUBLE   4
#define CHAR     5
#define POINTER  6
#define NTYPES   7

#define ZERO      0.0                                /* Floating point zero */

#define ONES_COMP_NEG(n, nb, incr)                                           \
    {if (nb == 8*sizeof(long))                                               \
        n = ~n + incr;                                                       \
     else                                                                    \
        {long msk;                                                           \
         msk = (1L << nb) - 1L;                                              \
         n   = (~n + incr) & msk;};}

int
 REVERSE_IN,
 REVERSE_OUT;

int
 SC_DECLARE(_PD_convert,
         (char **out, char **in, long nitems, int boffs,
          defstr *idp, defstr *odp,
          data_standard *hstd,
          long *pin_offs, long *pout_offs)),
 SC_DECLARE(_PD_null_pointer, (char *in, int bytes));

static int
 SC_DECLARE(_PD_get_bit, (char *base, int offs, int nby, int *ord));

extern void
 SC_DECLARE(_PD_convert_ascii, (char *out, char *in,
			     long nitems, int bpci, int offs)),
 SC_DECLARE(_PD_iconvert,
         (char **out, char **in, long nitems,
          long nbi, int ordi, long nbo, int ordo, int onescmp, int unsgned)),
 SC_DECLARE(_PD_fconvert,
         (char **out, char **in, long nitems, int boffs,
          long *infor, int *inord, long *outfor, int *outord,
          int l_order, int l_bytes, int onescmp));

static void
 SC_DECLARE(_PD_ncopy, 
            (char **out, char **in, long nitems, long bytepitem)),
/*  SC_DECLARE(_PD_byterev, (char **out, char **in, long nb, long nitems)), */
 SC_DECLARE(_PD_btrvout, (char *out, long nb, long nitems)),
 SC_DECLARE(_PD_insert_field,
         (long in_long, int m, char *out, int mo,
          int l_order, int l_bytes)),
 SC_DECLARE(_PD_set_bit, (char *base, int offs)),
 SC_DECLARE(_PD_reorder, (char *arr, long nitems, int nbytes, int *ord)),
 SC_DECLARE(_PD_byte_align, (char *out, char *in, long nitems, long *infor,
                                                   int *inord, int boffs));

/*--------------------------------------------------------------------------*/

/*                             DATA_STANDARDS                               */

/*--------------------------------------------------------------------------*/

/*
 * Floating Point Format Descriptor
 *
 * -   format[0] = # of bits per number
 * -   format[1] = # of bits in exponent
 * -   format[2] = # of bits in mantissa
 * -   format[3] = start bit of sign
 * -   format[4] = start bit of exponent
 * -   format[5] = start bit of mantissa
 * -   format[6] = high order mantissa bit
 * -   format[7] = bias of exponent
 *
 */

int
 FORMAT_FIELDS = 8,
 def_float_order[]    = {1, 2, 3, 4},
 def_double_order[]   = {1, 2, 3, 4, 5, 6, 7, 8},
 vax_float_order[]    = {2, 1, 4, 3},
 vax_double_order[]   = {2, 1, 4, 3, 6, 5, 8, 7},
 intel_float_order[]  = {4, 3, 2, 1},
 intel_double_order[] = {8, 7, 6, 5, 4, 3, 2, 1},
 ieee_float_order[]   = {1, 2, 3, 4},
 ieeea_double_order[] = {1, 2, 3, 4, 5, 6, 7, 8},
 ieeeb_double_order[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
 cray_float_order[]   = {1, 2, 3, 4, 5, 6, 7, 8};

long
 def_float[]    = {32L,  8L, 23L, 0L, 1L,  9L, 0L,   0x7FL},
 def_double[]   = {64L, 11L, 52L, 0L, 1L, 12L, 0L,  0x3FFL},

#ifdef GFLOAT
 vax_float[]    = {32L,  8L, 23L, 0L, 1L,  9L, 0L,   0x81L},
 vax_double[]   = {64L, 11L, 52L, 0L, 1L, 12L, 0L,  0x401L},
#else
 vax_float[]    = {32L,  8L, 23L, 0L, 1L,  9L, 0L,   0x81L},
 vax_double[]   = {64L,  8L, 55L, 0L, 1L,  9L, 0L,   0x81L},
#endif

 intel_float[]  = {32L,  8L, 23L, 0L, 1L,  9L, 0L,   0x7FL},
 intel_double[] = {64L, 11L, 52L, 0L, 1L, 12L, 0L,  0x3FFL},
 ieee_float[]   = {32L,  8L, 23L, 0L, 1L,  9L, 0L,   0x7FL},
 ieeea_double[] = {64L, 11L, 52L, 0L, 1L, 12L, 0L,  0x3FFL},
 ieeeb_double[] = {96L, 15L, 64L, 0L, 1L, 32L, 1L, 0x3FFEL},
 cray_float[]   = {64L, 15L, 48L, 0L, 1L, 16L, 1L, 0x4000L};

/*
 * Data standard for the different architectures
 *
 *   struct s_data_standard
 *      {int ptr_bytes;
 *       int short_bytes;
 *       int short_order;
 *       int int_bytes;
 *       int int_order;
 *       int long_bytes;
 *       int long_order;
 *       int longlong_bytes;
 *       int longlong_order;
 *       int float_bytes;
 *       long *float_format;
 *       int *float_order;
 *       int double_bytes;
 *       long *double_format;
 *       int *double_order;};
 *   
 *   typedef struct s_data_standard data_standard;
 *
 */

data_standard
 DEF_STD    = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, NORMAL_ORDER,                  /* size and order of short */
               4, NORMAL_ORDER,                    /* size and order of int */
               4, NORMAL_ORDER,                   /* size and order of long */
               4, NORMAL_ORDER,              /* size and order of LONG_LONG */
               4, def_float, def_float_order,           /* float definition */
               8, def_double, def_double_order},       /* double definition */
 IEEEA_STD  = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, NORMAL_ORDER,                  /* size and order of short */
               4, NORMAL_ORDER,                    /* size and order of int */
               4, NORMAL_ORDER,                   /* size and order of long */
               8, NORMAL_ORDER,              /* size and order of LONG_LONG */
               4, ieee_float, ieee_float_order,         /* float definition */
               8, ieeea_double, ieeea_double_order},   /* double definition */
 IEEEB_STD  = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, NORMAL_ORDER,                  /* size and order of short */
               2, NORMAL_ORDER,                    /* size and order of int */
               4, NORMAL_ORDER,                   /* size and order of long */
               4, NORMAL_ORDER,              /* size and order of LONG_LONG */
               4, ieee_float, ieee_float_order,         /* float definition */
               12, ieeeb_double, ieeeb_double_order},  /* double definition */
 IEEEC_STD  = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, NORMAL_ORDER,                  /* size and order of short */
               4, NORMAL_ORDER,                    /* size and order of int */
               4, NORMAL_ORDER,                   /* size and order of long */
               4, NORMAL_ORDER,              /* size and order of LONG_LONG */
               4, ieee_float, ieee_float_order,         /* float definition */
               12, ieeeb_double, ieeeb_double_order},  /* double definition */
 IEEED_STD  = {BITS_DEFAULT,                               /* bits per byte */
               8,                                        /* size of pointer */
               2, NORMAL_ORDER,                  /* size and order of short */
               4, NORMAL_ORDER,                    /* size and order of int */
               8, NORMAL_ORDER,                   /* size and order of long */
               8, NORMAL_ORDER,              /* size and order of LONG_LONG */
               4, ieee_float, ieee_float_order,         /* float definition */
               8, ieeea_double, ieeea_double_order},   /* double definition */
 IEEEE_STD  = {BITS_DEFAULT,                               /* bits per byte */
               8,                                        /* size of pointer */
               2, REVERSE_ORDER,                 /* size and order of short */
               4, REVERSE_ORDER,                   /* size and order of int */
               8, REVERSE_ORDER,                  /* size and order of long */
               8, REVERSE_ORDER,             /* size and order of LONG_LONG */
               4, ieee_float, intel_float_order,        /* float definition */
               8, ieeea_double, intel_double_order},   /* double definition */
 INTELA_STD = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, REVERSE_ORDER,                 /* size and order of short */
               2, REVERSE_ORDER,                   /* size and order of int */
               4, REVERSE_ORDER,                  /* size and order of long */
               4, REVERSE_ORDER,             /* size and order of LONG_LONG */
               4, intel_float, intel_float_order,       /* float definition */
               8, intel_double, intel_double_order},   /* double definition */
 INTELB_STD = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, REVERSE_ORDER,                 /* size and order of short */
               4, REVERSE_ORDER,                   /* size and order of int */
               4, REVERSE_ORDER,                  /* size and order of long */
               8, REVERSE_ORDER,             /* size and order of LONG_LONG */
               4, intel_float, intel_float_order,       /* float definition */
               8, intel_double, intel_double_order},   /* double definition */
 VAX_STD    = {BITS_DEFAULT,                               /* bits per byte */
               4,                                        /* size of pointer */
               2, REVERSE_ORDER,                 /* size and order of short */
               4, REVERSE_ORDER,                   /* size and order of int */
               4, REVERSE_ORDER,                  /* size and order of long */
               4, REVERSE_ORDER,             /* size and order of LONG_LONG */
               4, vax_float, vax_float_order,           /* float definition */
               8, vax_double, vax_double_order},       /* double definition */
 CRAY_STD   = {BITS_DEFAULT,                               /* bits per byte */
               8,                                        /* size of pointer */
               8, NORMAL_ORDER,                  /* size and order of short */
               8, NORMAL_ORDER,                    /* size and order of int */
               8, NORMAL_ORDER,                   /* size and order of long */
               8, NORMAL_ORDER,              /* size and order of LONG_LONG */
               8, cray_float, cray_float_order,         /* float definition */
               8, cray_float, cray_float_order};       /* double definition */

/*--------------------------------------------------------------------------*/

/*                            DATA_ALIGNMENTS                               */

/*--------------------------------------------------------------------------*/

/*
 * Word Alignment for the different architectures
 *
 *
 *   struct s_data_alignment
 *      {int char_alignment;
 *       int ptr_alignment;
 *       int short_alignment;
 *       int int_alignment;
 *       int long_alignment;
 *       int longlong_alignment;
 *       int float_alignment;
 *       int double_alignment;
 *       int struct_alignment;};
 *   
 *   typedef struct s_data_alignment data_alignment;
 *
 */

data_alignment
 RS6000_ALIGNMENT =  {1, 4, 2, 4, 4, 8, 4, 4, 0},
 SPARC_ALIGNMENT  =  {1, 4, 2, 4, 4, 4, 4, 8, 0},
 MIPS_ALIGNMENT   =  {1, 4, 2, 4, 4, 8, 4, 8, 0},
 UNICOS_ALIGNMENT =  {4, 8, 8, 8, 8, 8, 8, 8, 8},
 M68000_ALIGNMENT =  {1, 2, 2, 2, 2, 2, 2, 2, 0},
 INTELA_ALIGNMENT =  {1, 2, 2, 2, 2, 2, 2, 2, 0},
 INTELB_ALIGNMENT =  {4, 4, 4, 4, 4, 4, 4, 4, 0},
 INTELC_ALIGNMENT =  {1, 4, 2, 4, 4, 4, 4, 4, 0},
 VAX_ALIGNMENT    =  {1, 1, 1, 1, 1, 1, 1, 1, 0},
 MIPS64_ALIGNMENT =  {1, 8, 2, 4, 8, 8, 4, 8, 0},
 ALPHA64_ALIGNMENT = {1, 8, 2, 4, 8, 8, 4, 8, 0},
 DEF_ALIGNMENT    =  {1, 4, 4, 4, 4, 4, 4, 4, 0};

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* PD_CONVERT - convert from one machine format to another NITEMS of
 *            - type, TYPE, from IN and put them in OUT
 *            - ISTD and OSTD are the data format standards of IN and 
 *            - OUT respectively
 */

int PD_convert(out, in, intype, outtype, nitems, istd, ostd, hstd,
               pin_offs, pout_offs,
	       in_chart, out_chart, boffs, error)
   char **out;
   char **in;
   char *intype, *outtype;
   long nitems;
   data_standard *istd, *ostd, *hstd;
   long *pin_offs, *pout_offs;
   HASHTAB *in_chart, *out_chart;
   int boffs, error;
   {int ret, tmp;
    long i, mitems, in_incr, out_incr;
    char *mtype;
    defstr *idp, *odp, *midp, *modp;
    memdes *desc;

    if (_PD_indirection(outtype))
       {in_incr     = _PD_align(*pin_offs, intype, in_chart, &tmp);
        out_incr    = _PD_align(*pout_offs, outtype, out_chart, &tmp);
        *pin_offs  += in_incr;
        *pout_offs += out_incr;
        *in        += istd->ptr_bytes + in_incr;
        *out       += ostd->ptr_bytes + out_incr;
        return(TRUE);};

    idp = PD_inquire_table_type(in_chart, intype);
    if (idp == NULL)
       PD_error("BAD TYPE IN_CHART - PD_CONVERT", error);

    odp = PD_inquire_table_type(out_chart, outtype);
    if (odp == NULL)
       PD_error("BAD TYPE OUT_CHART - PD_CONVERT", error);

/* if members is non-NULL then it is a derived type */
    if (odp->members != NULL)
       {for (i = 0L; i < nitems; i++)
            {in_incr     = _PD_align(*pin_offs, intype, in_chart, &tmp);
             out_incr    = _PD_align(*pout_offs, outtype, out_chart, &tmp);
             *pin_offs  += in_incr;
             *pout_offs += out_incr;
             *in        += in_incr;
             *out       += out_incr;

             for (desc = odp->members; desc != NULL; desc = desc->next)
                 {mitems   = desc->number;
                  mtype    = desc->type;
                  in_incr  = _PD_align(*pin_offs, mtype, in_chart, &tmp);
                  out_incr = _PD_align(*pout_offs, mtype, out_chart, &tmp);

/* increment the offsets to the alignments */
                  *pin_offs  += in_incr;
                  *pout_offs += out_incr;
                  *in        += in_incr;
                  *out       += out_incr;

/* don't even think about converting pointers - they will be recomputed */
/* however, don't throw away information about whether or not pointer is null */
                  if (_PD_indirection(mtype))
                     {if (!_PD_null_pointer(*in, istd->ptr_bytes))
                         **out = 1;
                      *in        += istd->ptr_bytes;
                      *out       += ostd->ptr_bytes;
                      *pin_offs  += istd->ptr_bytes;
                      *pout_offs += ostd->ptr_bytes;
                      ret         = TRUE;}

/* check for direct primitives */
                  else if (_PD_prim_typep(desc->base_type, in_chart, error))
                     {modp = PD_inquire_table_type(out_chart, mtype);
                      if (modp == NULL)
                         PD_error("BAD OUT TYPE IN STRUCT - PD_CONVERT",
                                  error);

                      midp = PD_inquire_table_type(in_chart, mtype);
                      if (midp == NULL)
                         PD_error("BAD IN TYPE IN STRUCT - PD_CONVERT",
                                  error);

		      ret = _PD_convert((char **) out, in, mitems, boffs,
					midp, modp, hstd,
					pin_offs, pout_offs);}

/* recurse for direct derived types */
                  else
                     ret = PD_convert(out, in, mtype, mtype, mitems,
                                      istd, ostd, hstd, pin_offs, pout_offs,
                                      in_chart, out_chart, boffs, error);

                  if (!ret)
                     PD_error("STRUCT CONVERSION FAILED - PD_CONVERT",
                              error);};};}

/* if members is NULL then it is a primitive type */
    else
       {ret = _PD_convert((char **) out, in, nitems, boffs, idp, odp,
                          hstd, pin_offs, pout_offs);
        if (!ret)
           PD_error("PRIMITIVE CONVERSION FAILED - PD_CONVERT",
                    error);};

    return(ret);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_NULL_POINTER - if the input contains only null bytes, return TRUE
 *                  - otherwise, return FALSE
 */

int _PD_null_pointer(in, bytes)
   char *in;
   int bytes;
   {int i;

    for (i = 0; i < bytes; i++)
        if (*in++)
           return(FALSE);

    return(TRUE);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_PRIM_TYPEP - returns TRUE if the given struct member is a primitive
 *                - data type and FALSE otherwise
 */

int _PD_prim_typep(memb, chrt, error)
   char *memb;
   HASHTAB *chrt;
   int error;
   {defstr *pd;

    pd = PD_inquire_table_type(chrt, memb);
    if (pd == NULL)
       PD_error("BAD TYPE FROM STRUCTURE CHART - _PD_PRIM_TYPEP", error);

    return((pd->members == NULL));}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_CONVERT - convert primitive types from one machine format to
 *             - another.  Guaranteed that there will be no indirects here.
 *             - Convert NITEMS of type, TYPE, from IN and
 *             - put them in OUT
 *             - ISTD defines the data format of the data from IN
 *             - PIN_OFFS and POUT_OFFS are pointers to external offset
 *             - counters and they are incremented to account for
 *             - data alignment
 *             - returns TRUE iff successful
 */

int _PD_convert(out, in, nitems, boffs, idp, odp, hstd, pin_offs, pout_offs)
   char **out;
   char **in;
   long nitems;
   int boffs;
   defstr *idp, *odp;
   data_standard *hstd;
   long *pin_offs, *pout_offs;
   {int l_order, l_bytes, in_bits, onescmp, unsgned, in_unsgned, out_unsgned, ret;
    long in_bytes, out_bytes, nbi, nbo;
    int in_flag, out_flag, *in_order, *out_order;
    long *in_format, *out_format;
    char *in_type, *out_type;
    int i, *intorder;

    in_type       = idp->type;
    out_type      = odp->type;
    in_bits       = idp->size_bits;
    in_bytes      = idp->size;
    out_bytes     = odp->size;
    in_order      = idp->order;
    out_order     = odp->order;
    in_flag       = idp->order_flag;
    out_flag      = odp->order_flag;
    in_format     = idp->format;
    out_format    = odp->format;
    onescmp       = idp->onescmp;
    in_unsgned    = idp->unsgned;
    out_unsgned   = odp->unsgned;

    if ((strchr(in_type, '*') != NULL) || (strchr(out_type, '*') != NULL))
       return(FALSE);

    unsgned = (!in_unsgned && !out_unsgned) ? FALSE : TRUE;

    l_order = hstd->long_order;
    l_bytes = hstd->long_bytes;

    ret = TRUE;

    nbi = in_bytes*nitems;
    nbo = out_bytes*nitems;

/* if direct types are the same and non-converting just copy them over */
    if ((strcmp(odp->type, idp->type) == 0) &&
	(odp->convert == 0) && (idp->convert == 0) &&
	(nbi == nbo))
       {_PD_ncopy(out, in, nitems, in_bytes);

        *pin_offs  += nbi;
        *pout_offs += nbo;}

/* handle floating point conversions */
    else if ((in_format != NULL) && (out_format != NULL))
       {_PD_fconvert(out, in, nitems, boffs, in_format, in_order,
                     out_format, out_order, l_order, l_bytes, onescmp);

        *pin_offs  += nbi;
        *pout_offs += nbo;}

/* handle integral bitstreams */
    else if (in_bits > 0)
       {int ityp;

	if (out_bytes == sizeof(char))
	   ityp = SC_CHAR_I;

	else if (out_bytes == sizeof(long))
	   ityp = SC_LONG_I;

	else if (out_bytes == sizeof(short))
	   ityp = SC_SHORT_I;

	else if (out_bytes == sizeof(int))
	   ityp = SC_INTEGER_I;

	else
	   return(FALSE);

/* unpack the bitstream into a bytestream */
	ret = _PD_unp_bits(*out, *in, ityp, in_bits,
			   0, nitems, nitems, boffs);

/* convert characters */
        if (strcmp(in_type, SC_CHAR_S) == 0)
	   _PD_convert_ascii(*out, *in, nitems, in_bits, 0);

/* convert integers */
        else
	   {intorder = (int *) SC_alloc_na(out_bytes, sizeof(int),
					   "_PD_CONVERT:intorder",
					   FALSE);
            if (out_flag == NORMAL_ORDER)
               for (i = 0; i < out_bytes; intorder[i] = i + 1, i++);
            else                         
               for (i = 0; i < out_bytes; intorder[i] = out_bytes - i, i++);

            if (!unsgned)
      	        _PD_sign_extend(*out, nitems, out_bytes,
			       in_bits, intorder);

            if (onescmp)
               _PD_ones_complement(*out, nitems, out_bytes, intorder);

            SFREE(intorder);

	    *in        += nbi;
	    *out       += nbo;
	    *pin_offs  += nbi;
	    *pout_offs += nbo;};}

/* handle integer conversions */
    else if ((in_flag != -1) && (out_flag != -1))
       {_PD_iconvert(out, in, nitems,
                     (int) in_bytes, in_flag,
                     (int) out_bytes, out_flag, onescmp, unsgned);

        *pin_offs  += nbi;
        *pout_offs += nbo;}

/* handle character or unconverted types */
    else
       {_PD_ncopy(out, in, nitems, in_bytes);

        *pin_offs  += nbi;
        *pout_offs += nbo;};

    return(ret);}

/*--------------------------------------------------------------------------*/

/*                           ASCII CONVERSION ROUTINES                      */

/*--------------------------------------------------------------------------*/

/* _PD_CONVERT_ASCII - translate characters from BCPI bit ASCII to
 *                   - 8-bit ASCII
 *                   - NOTE: this is only here to allow PDB to read old
 *                   -       machine data which may not be 8 bit ASCII
 *                   -
 *                   - Inputs : IN     - input buffer
 *                   -          NITEMS - number of fields to translate
 *                   -          BCPI   - bits per character on input
 *                   -          OFFS   - zero-origin bit offset from IN
 *                   -                   to start of data
 *                   - Output:  OUT    - output buffer
 */

void _PD_convert_ascii(out, in, nitems, bpci, offs)
   char *out, *in;
   long nitems;
   int bpci, offs;
   {long i;

/* translate chars by adding a blank (0x20) character
 * to give upper-case letters then or-ing the sum with a blank
 * to give lower-case letters
 */
    for (i = 0; i < nitems; i++)
        out[i] = (out[i] + ' ') | ' ';

    return;}

/*--------------------------------------------------------------------------*/

/*                      INTEGER CONVERSION ROUTINES                         */

/*--------------------------------------------------------------------------*/

/* _PD_ICONVERT - convert integers of nbi bytes to integers of nbo bytes
 *              - the number of bytes for each integer are given
 */

void _PD_iconvert(out, in, nitems, nbi, ordi, nbo, ordo, onescmp, unsgned)
   char **out, **in;
   long nitems, nbi;
   int ordi;
   long nbo;
   int ordo, onescmp, unsgned;
   {long i;
    int j;
    char *lout, *lin, *po, *pi;
    char s_extend;

    lin = *in;
    lout = *out;

    s_extend = unsgned ? 0 : 0xff;

/* convert nitems integers
 * test sign bit to properly convert negative integers
 */
    if (nbi < nbo)
       {if (ordi == REVERSE_ORDER)
	   {for (j = nbi; j < nbo; j++)
                {po = lout + j - nbi;
                 pi = lin + nbi - 1;
                 for (i = 0L; i < nitems; i++)
                     {*po = (*pi & 0x80) ? s_extend : 0;
                      po += nbo;
		      pi += nbi;};};
	    for (j = nbi; j > 0; j--)
                {po = lout + nbo - j;
                 pi = lin + j - 1;
                 for (i = 0L; i < nitems; i++)
                     {*po = *pi;
                      po += nbo;
		      pi += nbi;};};}
        else
	   {for (j = nbi; j < nbo; j++)
                {po = lout + j - nbi;
                 pi = lin;
                 for (i = 0L; i < nitems; i++)
                     {*po = (*pi & 0x80) ? s_extend : 0;
                      po += nbo;
		      pi += nbi;};};
	    for (j = 0; j < nbi; j++)
                {po = lout + j + nbo - nbi;
                 pi = lin + j;
                 for (i = 0L; i < nitems; i++)
                     {*po = *pi;
                      po += nbo;
		      pi += nbi;};};};}

    else if (nbi >= nbo)
       {if (ordi == REVERSE_ORDER)
           {for (j = nbo; j > 0; j--)
                {po = lout + nbo - j;
                 pi = lin + j - 1;
                 for (i = 0L; i < nitems; i++)
                     {*po = *pi;
                      po += nbo;
		      pi += nbi;};};}
        else
           {for (j = nbi - nbo; j < nbi; j++)
                {po = lout + j - nbi + nbo;
                 pi = lin + j;
                 for (i = 0L; i < nitems; i++)
                     {*po = *pi;
                      po += nbo;
		      pi += nbi;};};};};

/* if the input used ones complement arithmetic convert to twos complement */
    if (onescmp)
       _PD_ones_complement(*out, nitems, nbo, NULL);
                          
    if (ordo == REVERSE_ORDER)
       _PD_btrvout(*out, nbo, nitems);

    *in  += nitems*nbi;
    *out += nitems*nbo;

    return;}

/*--------------------------------------------------------------------------*/

/*                       FLOAT CONVERSION ROUTINES                          */

/*--------------------------------------------------------------------------*/

/* Parametrized Data Conversion Method
 *
 * Floating point formats are characterized by a set of parameters which
 * describe the fundamental elements of a floating point number. These are
 *
 *  Sign     - always assumed to be a single bit
 *           - requires bit offset
 *  Exponent - assumed to be a biased integer smaller than 32 bits
 *           - (this allows the conversion to use a long on all known
 *           - platforms - an exponent greater than 32 bits long would
 *           - allow much larger numbers than should be needed for
 *           - scientific computations)
 *           - requires a bit offset, a bit length, and a bias
 * Mantissa  - assumed to be a bitstream of arbitrary length
 *           - requires a bit offset and a bit length
 * HMB       - in all floating point representations the mantissa is
 *           - normalized so that the most significant bit is one.
 *           - in some formats the one is explicitly included in the
 *           - representation and in others it is only implicit
 *           - this gives some formats an extra bit of precision.
 *           - requires a flag which is TRUE if the HMB is explicit
 * 
 * Two other factors involved are: the byte order which could be
 * mixed with the bit layout of the numbers but isn't in actual practice
 * on current machines; and whether one's complement or two's complement
 * arithmetic is used. Modern machines all use two's complement arithmetic
 * and the model used here and now is that data from one's complement
 * machines is to be read only.  This restriction is relatively easy
 * to relax, but there is no evidence that it should be.
 *
 * An issue which is not a problem in the current implementation is that
 * old machines with byte sizes other than 8 bits can be accomodated
 * because the conversions treat the input and output as bitstreams
 * instead of bytestreams.
 *
 * The conversion process is summarized as follows:
 *   1) Extract the sign bit and exponent field from the input number
 *   2) Subtract the bias of the source format and add the bias
 *      of the target format
 *   3) Check for overflow in the exponent
 *   4) Insert the new exponent and the sign bit in the target stream
 *   5) Copy the mantissa bits from the source to the target
 *      compensating for differences in the HMB between the two
 *      formats
 *   6) Take care of any known anomalies - e.g. CRAY format is
 *      inconsistent in that the HMB is explicitly on for all numbers
 *      with the exception of 0.0
 *   7) Reorder the bytes of the target stream appropriately
 *
 * The floating point formats for a variety of platforms are supplied by
 * PDBLib and are defined at the top of this file
 *
 */

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_FCONVERT - general floating point conversion routine
 *              - convert from floating point format specified by infor
 *              - to format specified by outfor
 *              -
 *              - floating point format specification:
 *              -
 *              -   format[0] = # of bits per number
 *              -   format[1] = # of bits in exponent
 *              -   format[2] = # of bits in mantissa
 *              -   format[3] = start bit of sign
 *              -   format[4] = start bit of exponent
 *              -   format[5] = start bit of mantissa
 *              -   format[6] = high order mantissa bit (CRAY needs this)
 *              -   format[7] = bias of exponent
 */
#define MBLOCKS 256
#define MBYTES   16


void _PD_fconvert(out, in, nitems, boffs, infor, inord, outfor, outord,
		  l_order, l_bytes, onescmp)
   char **out;
   char **in;
   long nitems;
   int boffs;
   long *infor;
   int *inord;
   long *outfor;
   int *outord, l_order, l_bytes, onescmp;
   {long i, j, expn_max, hexpn, DeltaBias, hmbo, hmbi;
    int nbits, inbytes, outbytes;
    int indxout, inrem, outrem, dindx;
    int bi_sign, bo_sign, bi_exp, bo_exp, bi_mant, bo_mant;
    int nbi_exp, nbo_exp, nbi, nbo;
    char *lout, *lin;
    char *aligned, *insave;
   
    unsigned char *rout;

    long start, end, count, sign_byte, exp_byte;
    long hman_byte, in_man_byte, out_man_byte;
    int in_man_bit, out_man_bit, nbitsout;
    int sign_bit, exp_bit, hman_bit, rshift;
    int numleft, nb_mant_rem, remainder, k, nleft;
    unsigned char *out_mbptr, *in_mbptr, *outptr, *inptr;
    char mask, mask1, mask2, cmask;
    unsigned char *sbptr, *ebptr, *ebptrsave, *hman_bptr;
    long loverflow, lunderflow, lreorder, lreformat;
    char *bufin, *btemp, *ctemp;

    long expn_save[MBLOCKS];
    int sign_save[MBLOCKS];
    char inreorder[MBLOCKS*MBYTES];

    aligned = NULL;
    hman_byte = 0;

    nbi     = infor[0];
    nbo     = outfor[0];
    nbi_exp = infor[1];
    nbo_exp = outfor[1];

    bi_sign = infor[3];
    bo_sign = outfor[3];
    bi_exp  = infor[4];
    bo_exp  = outfor[4];
    bi_mant = infor[5];
    bo_mant = outfor[5];

    hmbo    = (outfor[6] & 1L);
    hmbi    = (infor[6] & 1L);

    inbytes   = (nbi + 7) >> 3;
    outbytes  = (nbo + 7) >> 3;
    DeltaBias = outfor[7] + hmbo - infor[7] - hmbi;
    hexpn     = 1L << (outfor[1] - 1L);
    expn_max  = (1L << outfor[1]) - 1L;

    if ((nbi % 8 != 0) || boffs)
       {aligned = SC_alloc_na(inbytes*nitems, 1L,
			      "_PD_FCONVERT:aligned", FALSE);
        _PD_byte_align(aligned, *in, nitems, infor, inord, boffs);
        insave = *in;
        *in = aligned;}

/* check for cases where only difference between formats is in byte order */
    lreformat = FALSE;
    for (i = 0; i < 8; i++)
        {if (infor[i] != outfor[i])
            {lreformat = TRUE;
             break;};}

    if (!lreformat)
       {lreorder = FALSE;

/* check to see if input byte order is different than output byte order */
        for (i = 0; i < inbytes; i++)
            {if (inord[i] != outord[i])
                {lreorder = TRUE;
                 break;};}

/*  reorder bytes and return if only difference is in byte order */
        if (lreorder)
           {lin  = *in;
            lout = *out;
            for (i = 0; i < inbytes; i++) /* inbytes == outbytes */
                {btemp = &lin[inord[i] - 1];
                 ctemp = &lout[outord[i] - 1];
                 for (j = 0; j < nitems; j++, ctemp += inbytes, btemp += inbytes)
                     {*ctemp = *btemp;};}
            *in  += nitems*inbytes;
            *out += nitems*outbytes;
            return;};}

/* check to see if input needs reordering */
    lreorder = FALSE;
    for (i = 0; i < inbytes; i++)
        {if (inord[i] != (i+1))
            {lreorder = 1;
             break;};}

/* if input needs reordering, reorder into a buffer */
    lout = *out;
    if (lreorder)
       lin = inreorder;
    else
       lin = *in;

/* zero out the output buffer */
    memset(*out, 0, nitems*outbytes);

    start = 0;
    end   = min(nitems, MBLOCKS);
    count = 0;  /* count of items processed */

/* set up sign bit byte index and bit index */
    sign_byte = bi_sign >> 3;
    sign_bit  = bi_sign % 8;

/* set up exponent location variables */
    exp_byte = bi_exp >> 3;
    exp_bit  = bi_exp % 8;

/* set up mantissa location variables */
    in_man_byte = bi_mant >> 3;
    in_man_bit  = bi_mant % 8;

    out_man_byte = bo_mant >> 3;
    out_man_bit  = bo_mant % 8;

    dindx = hmbo - hmbi;

/* if input high mantissa bit (HMB) is assumed 1 and not written (e.g. IEEE)
 * but output HMB is assumed 0 (e.g. CRAY) write the input starting at
 * the output HMB+1 and set the HMB
 */
    if (dindx > 0)
       {hman_bit    = out_man_bit;
        hman_byte   = out_man_byte;
        out_man_bit = (out_man_bit + dindx) % 8;
        if (out_man_bit == 0)
	   out_man_byte++;} 

/* if input HMB is assumed 0 (e.g. CRAY) 
 * but output HMB is assumed 1 and not written (e.g. IEEE) take the input
 * from HMB+1 and write it to output HMB
 */
    else if (dindx < 0)
       {in_man_bit = (in_man_bit - dindx) % 8;
        if (in_man_bit == 0)
	   in_man_byte++;}

   while (count < nitems)

/* reorder the input into a buffer */
         {if (lreorder)
             {bufin = *in + (count * inbytes) - 1;
              for (i = 0; i < inbytes; i++)
                  {btemp = &bufin[inord[i]];
                   ctemp = lin + i;
                   for (j = start; j < end; j++, btemp += inbytes, ctemp += inbytes)
                       {*ctemp   = *btemp;};};}
     
          ebptr     = (unsigned char *)lin + exp_byte + (!lreorder) * (count * inbytes);
          sbptr     = (unsigned char *)lin + sign_byte + (!lreorder) * (count * inbytes);
          in_mbptr  = (unsigned char *)lin + in_man_byte + (!lreorder) * (count * inbytes);
          out_mbptr = (unsigned char *)lout + out_man_byte + (count * outbytes);
          hman_bptr = (unsigned char *)lout + hman_byte + (count * outbytes);

/* get the sign bit, saving it in sign_save */       
          mask = 1 << (7 - sign_bit);
          for (i = start; i < end; i++, sbptr += inbytes)
              {sign_save[i] = *sbptr & mask;};

          inrem = nbi_exp;
          nbits = 8 - exp_bit;
          mask  = (1 << nbits) - 1;
          memset(expn_save, 0, (end-start)*sizeof(long));

          ebptrsave = ebptr;
          rshift    = 0;
          while (inrem > 0)

/* get the exponent */ 
                {for (i = start; i < end; i++, ebptr += inbytes )
                     {expn_save[i] = (expn_save[i] << nbits) |
                                     ((*ebptr >> rshift) & mask);};

                 inrem    -= nbits;
                 nbits     = min(8, inrem);
                 rshift    = 8 - nbits;
                 mask      = (1 << nbits) - 1;
                 ebptr     = ebptrsave + 1;
                 ebptrsave = ebptr;};

          if (onescmp)
             {for (i = start; i < end; i++)
                  {if (sign_save[i])
                      {ONES_COMP_NEG(expn_save[i], nbi_exp, 1L);}
                   else
                      expn_save[i] += (expn_save[i] < hexpn);};};

/* add the bias and store the exponent */
          loverflow  = FALSE;
          lunderflow = FALSE;
          for (i = start; i < end; i++, bo_exp  += nbo, bo_sign += nbo)
              {if (expn_save[i] != 0)
		  expn_save[i] += DeltaBias;

               if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                  {_PD_insert_field(expn_save[i], nbo_exp, lout, bo_exp,
                                    l_order, l_bytes);
                   if (sign_save[i]) 
                       _PD_set_bit(lout, bo_sign);}

               else if (expn_max <= expn_save[i])
                  {loverflow = TRUE;
                   _PD_insert_field(expn_max, nbo_exp, lout, bo_exp,
                                    l_order, l_bytes);
                   if (sign_save[i])
		      _PD_set_bit(lout, bo_sign);}

               else   /* expn_save[i] < 0 */
                  lunderflow = TRUE;};

/* if input high mantissa bit (HMB) is assumed 1 and not written (e.g. IEEE)
 * but output HMB is assumed 0 (e.g. CRAY) write the input starting at
 * the output HMB+1 and set the HMB
 */
          if (dindx > 0)
             {mask   = 1 << (7 - hman_bit);
              outptr = hman_bptr;

              if (loverflow || lunderflow)
                 {for (i = start; i < end; i++, outptr += outbytes)
                      {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
			  *outptr |= mask;};}
              else
		 {for (i = start; i < end; i++, outptr += outbytes)
		      *outptr |= mask;};};

          nbitsout = 8 - out_man_bit;
          mask     = (1 << nbitsout) - 1;
          outptr   = out_mbptr;
          inptr    = in_mbptr;
          inrem    = infor[2];
          outrem   = outfor[2];
          if (dindx > 0)
	     outrem -= dindx;
          else if (dindx < 0)
	     inrem += dindx;

/* will the chunk of in mantissa in first byte fit in the first byte
 * of out mantissa?
 */ 
          if (in_man_bit >= out_man_bit)

/* it will fit - store it */
             {if (loverflow || lunderflow)
                 {if (onescmp)
		     {cmask = (1 << (8 - in_man_bit)) - 1;
                      for (i = start; i < end; i++, outptr += outbytes, inptr += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              {if (sign_save[i])
				  *outptr |=  (~(*inptr & cmask) << (in_man_bit - out_man_bit))  & mask;
                               else
				  *outptr |=  (*inptr << (in_man_bit - out_man_bit))  & mask;};};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              *outptr |= (*inptr << (in_man_bit - out_man_bit))  & mask;};};}

/* no overflow */
              else
                 {if (onescmp)
                     {cmask = (1 << (8 - in_man_bit)) - 1;
                      for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if (sign_save[i])
			      *outptr |=  (~(*inptr & cmask) << (in_man_bit - out_man_bit))  & mask;
                           else
			      *outptr |=  (*inptr << (in_man_bit - out_man_bit))  & mask;};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          *outptr |= (*inptr << (in_man_bit - out_man_bit))  & mask;};};
 
/* fill in the rest of the first output byte with the first
 * part of the second input byte
 */
              numleft   = in_man_bit - out_man_bit;
              remainder = 0;
              if (numleft > 0)
                 {mask      = (1 << numleft) - 1;
                  inptr     = ++in_mbptr;
                  outptr    = out_mbptr;
                  remainder = 8 - numleft;
                  if (loverflow || lunderflow)
                     {if (onescmp)
                         {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                              {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                                  {if (sign_save[i])
				      *outptr |= ~(*inptr >> remainder) & mask;
                                   else
				      *outptr |=  (*inptr >> remainder) & mask;};};}
                      else
                         {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                              {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                                  *outptr |= (*inptr >> remainder) & mask;};};}
                  else 
                     {if (onescmp)
                         {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                              {if (sign_save[i])
				  *outptr |= ~(*inptr >> remainder) & mask;
                               else
				  *outptr |=  (*inptr >> remainder) & mask;};}
                      else
                         {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                              *outptr |= (*inptr >> remainder) & mask;};};};}

/* in_man_bit < out_man_bit */
          else

/* no it won't fit */
             {remainder = out_man_bit - in_man_bit; 
              if (loverflow || lunderflow)
                 {if (onescmp)
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              {if (sign_save[i])
				  *outptr |= ~(*inptr >> remainder)  & mask;
                               else
				  *outptr |=  (*inptr >> remainder)  & mask;};};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              *outptr |= (*inptr >> remainder)  & mask;};};}       
              else
                 {if (onescmp)
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if (sign_save[i])
			      *outptr |= ~(*inptr >> remainder)  & mask;
                           else
			      *outptr |=  (*inptr >> remainder)  & mask;};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          *outptr |= (*inptr >> remainder)  & mask;};};};

          inrem  -= nbitsout;
          outrem -= nbitsout;          
          outptr  = ++out_mbptr; /* begin storing to the beginning of the next */
                                 /* sink byte.                                 */
          inptr   = in_mbptr;    /* from the byte with the remainder. */

/* how many full bytes of mantissa left? */
          nb_mant_rem = inrem >> 3;
          nb_mant_rem = min(nb_mant_rem, outrem >> 3);
          mask1 = (1 << remainder) -1;
          mask2 = (1 << (8 - remainder)) -1;
       
          for (k = 0; k < nb_mant_rem; k++)
              {outptr = out_mbptr + k;
               inptr  = in_mbptr  + k;
               if (loverflow || lunderflow)
                  {if (onescmp)

/* move the mantissa over bytewise */
                      {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                           {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                               {if (sign_save[i])
				   *outptr = ((~(*inptr) & mask1) << (8 - remainder)) |
				             (~(*(inptr + 1) >> remainder) & mask2);
			         else
				    *outptr = ((*inptr & mask1) << (8 - remainder)) |
				              ((*(inptr + 1) >> remainder) & mask2);};};}
                   else

/* move the mantissa over bytewise */
                      {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                           {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                               *outptr = ((*inptr & mask1) << (8 - remainder)) |
                                         ((*(inptr + 1) >> remainder) & mask2);};};}
               else
                  {if (onescmp)

/* move the mantissa over bytewise */
                      {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                           {if (sign_save[i])
			       *outptr = ((~(*inptr) & mask1) << (8 - remainder)) |
				         (~(*(inptr + 1) >> remainder) & mask2);
                            else
			       *outptr = (((*inptr) & mask1) << (8 - remainder)) |
				         ((*(inptr + 1) >> remainder) & mask2);};}
                   else

/* move the mantissa over bytewise */
                      {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                           {*outptr = ((*inptr & mask1) << (8 - remainder)) |
                                      ((*(inptr + 1) >> remainder) & mask2);};};};}

          out_mbptr += nb_mant_rem;
          in_mbptr  += nb_mant_rem;
          nbitsout = (nb_mant_rem << 3);
          inrem -= nbitsout;
          outrem -= nbitsout;

/* store the last bits */
          nleft = min(inrem, outrem);
          if (nleft)
             {mask = ((1 << nleft) - 1) << (8 - nleft);
              outptr = out_mbptr;
              inptr  = in_mbptr;
              if (loverflow || lunderflow)
                 {if (onescmp)
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              {if (sign_save[i])
				  *outptr = ~(*inptr << (8 - remainder)) & mask;
                               else
				  *outptr =  (*inptr << (8 - remainder)) & mask;};};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if ((0 < expn_save[i]) && (expn_save[i] < expn_max))
                              *outptr = (*inptr << (8 - remainder)) & mask;};};}
              else
                 {if (onescmp)
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          {if (sign_save[i])
			      *outptr = ~(*inptr << (8 - remainder)) & mask;
                           else
			      *outptr = (*inptr << (8 - remainder)) & mask;};}
                  else
                     {for (i = start; i < end; i++, outptr += outbytes, inptr  += inbytes)
                          *outptr = (*inptr << (8 - remainder)) & mask;};};};

          count += end - start;
          end    = min(nitems-count, MBLOCKS);} /* end while (count < nitems) */

/* handle CRAY inconsistency which has zero as the only floating point
 * number with a 0 in the HMB
 * also problem for IEEE 96 bit float - fixed by Dave Munro
 */
    if (hmbo)
       {int j, mask = (1 << (7 - bo_mant % 8));

        indxout = outfor[5]/8;
        rout    = (unsigned char *) *out;
        for (i = 0L; i < nitems; i++, rout += outbytes)
            {for (j = 0; j < outbytes; j++)
                 if ((j == indxout) ? (rout[j] != mask) : rout[j])
                    break;
             if (j == outbytes)
                rout[indxout] = 0;};};

    if (*in == aligned)
       {SFREE(aligned);
        *in = insave;}

/* put the output bytes into the specified order */
    _PD_reorder(*out, nitems, outbytes, outord);

    *in  += nitems*inbytes;
    *out += nitems*outbytes;

    return;}

/*--------------------------------------------------------------------------*/

/*                             HELPER ROUTINES                              */

/*--------------------------------------------------------------------------*/

/* _PD_NCOPY - copy the NITEMS of size BYTEPITEM from IN to OUT */

static void _PD_ncopy(out, in, nitems, bytepitem)
   char **out;
   char **in;
   long nitems, bytepitem;
   {long nbytes;

    nbytes = nitems*bytepitem;
    memcpy(*out, *in, nbytes);

    *in  += nbytes;
    *out += nbytes;

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_UNP_BITS - unpack an array that contains a bitstream
 *              - arguments are:
 *              -   ITYP    the target type of the data when unpacked
 *              -   NBITS   the number of bits per item
 *              -   PADSZ   the number of bits of pad preceding the fields
 *              -   FPP     the number of fields per pad
 *              -   NITEMS  the number of items expected
 *              -   OFFS    the bit offset of the first pad
 */

int _PD_unp_bits(out, in, ityp, nbits, padsz, fpp, nitems, offs)
   char *out, *in;
   int ityp, nbits, padsz, fpp;
   long nitems, offs;
   {long i, bita, fld, np, *pl;
    char *pc;
    int *pi;
    short *ps;

    switch (ityp)
       {case SC_CHAR_I :
	     pc = (char *) out;
	     break;
	case SC_SHORT_I :
	     ps = (short *) out;
	     break;
        case SC_INTEGER_I :
	     pi = (int *) out;
	     break;
	case SC_LONG_I :
	     pl = (long *) out;
	     break;};

    for (i = 0L; i < nitems; i++)
        {np   = 1 + i/fpp;
	 bita = np*padsz + i*nbits + offs;
	 fld  = _PD_extract_field(in, bita, nbits, INT_MAX, NULL);

	 switch (ityp)
	    {case SC_CHAR_I :
	          pc[i] = (char) fld;
		  break;
             case SC_SHORT_I :
                  ps[i] = (short) fld;
                  break;
             case SC_INTEGER_I :
                  pi[i] = (int) fld;
                  break;
             case SC_LONG_I :
                  pl[i] = (long) fld;
                  break;};};

    return(TRUE);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_SIGN_EXTEND - sign extend integers which may come from odd bit
 *                 - sized sources
 */

void _PD_sign_extend(out, nitems, nbo, nbti, ord)
   char *out;
   long nitems;
   int nbo, nbti, *ord;
   {int i, j, sba, tsba, sign, indx;
    unsigned char *lout, mask;

    sba = 8*nbo - nbti;

/* if sba is less than zero we have truncated the integers and really
 * don't know about the sign
 */
    if (sba < 0)
       return;

    lout = (unsigned char *) out;
    for (i = 0L; i < nitems; i++)
        {sign = _PD_get_bit((char *) lout, sba, nbo, ord);
         tsba = sba;
         if (sign)
            {for (j = 0; (tsba > 8); j++, tsba -= 8)
	         {indx = (ord != NULL) ? ord[j] - 1 : j;
		  lout[indx] = 0xFF;};

	     mask = ((1 << tsba) - 1) << (8 - tsba);
	     indx = (ord != NULL) ? ord[j] - 1 : j;
	     lout[indx] |= mask;};

	 lout += nbo;};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_ONES_COMPLEMENT - convert ones complement integers to twos
 *                     - complement
 *                     - NOTE: modern machines use twos complement arithmetic
 *                     -       and therefore this is a one way conversion
 */

void _PD_ones_complement(out, nitems, nbo, order)
   char *out;
   long nitems;
   int nbo;
   int *order;
   {int i, j, indx;
    unsigned int carry;
    unsigned char *lout;

    lout = (unsigned char *) out;
    for (i = 0L; i < nitems; i++)
        {indx = (order != NULL) ? order[0] - 1 : 0;
         if (lout[indx] & 0x80 )
	    {carry = 1;
	     for (j = nbo-1; (j >= 0) && (carry > 0); j--)
	         {indx = (order != NULL) ? order[j] - 1 : j;
                  carry  += lout[indx];
		  lout[indx] = carry & 0xFF;
		  carry   = (carry > 0xFF);};};

	 lout += nbo;};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_BTRVOUT - byte reverse nitems words
 *             - each word is nb bytes long where nb is even
 */

static void _PD_btrvout(out, nb, nitems)
   char *out;
   long nb;
   long nitems;
   {long i, jl, jh, nbo2;
    char tmp;
    char *p1, *p2;

    nbo2 = nb >> 1;
    for (jl = 0; jl < nbo2; jl++)
        {jh = nb - jl - 1;
         p1 = out + jh;
         p2 = out + jl;
	 for (i = 0L; i < nitems; i++)
             {tmp = *p1;
              *p1 = *p2;
              *p2 = tmp;
              p1 += nb;
              p2 += nb;};};

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_EXTRACT_FIELD - make a copy of the bit field specified by the starting
 *                   - bit, OFFS, and the number of bits, NBI, from the byte
 *                   - array pointed to by IN
 *                   - all indexing is 0 based
 *                   - the copy is to be put in a long and returned
 *                   - this imposes a 32 bit limit (minimum) so repeated calls
 *                   - must be made for longer fields
 */

long _PD_extract_field(in, offs, nbi, nby, ord)
   char *in;
   int offs, nbi, nby, *ord;
   {long n, bit_field;
    int offy, tgt, ind;
    unsigned char mask, bpb;

    bit_field = 0L;

/* move past the apropriate number of bytes so that the start bit is
 * in the first byte
 * OFFY is the offset of the byte containing the bit OFFS
 */
    n    = offs >> 3;
    offy = n % nby;
    n   -= offy;
    offs = offs % 8;

/* advance the pointer past the unneeded items */
    in += n;

    bpb  = 8 - offs;
/*    ind  = (ord == NULL) ? offy++ : (ord[offy++] - 1); */
    if (ord == NULL)
       ind = offy++;
    else
       {if (offy >= nby)
           {offy -= nby;
	    in += nby;};
	ind = (ord[offy++] - 1);};

    tgt  = in[ind];
    mask = (1 << bpb) - 1;
    bit_field = ((bit_field << bpb) | (tgt & mask));
    nbi -= bpb;
    if (nbi < 0)
       bit_field = bit_field >> (-nbi);
    else
       {for (; nbi > 0; nbi -= bpb)
            {/* ind  = (ord == NULL) ? offy++ : (ord[offy++] - 1); */
	     if (ord == NULL)
	        ind = offy++;
	     else
	        {if (offy >= nby)
		    {offy -= nby;
		     in += nby;};
		 ind = (ord[offy++] - 1);};
		 
             tgt  = in[ind];
             bpb  = min(nbi, 8);
             mask = (1 << bpb) - 1;
             bit_field = ((bit_field << bpb) |
                          ((tgt >> (8 - bpb)) & mask));};};

    return(bit_field);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_INSERT_FIELD - copy the least significant NB bits from the given long
 *                  - into the byte array pointed to by OUT
 *                  - all indexing is 0 based
 *                  - OFFS is the offset from the beginning of OUT in bits
 *                  - this assumes that the output bit array is initialized
 *                  - to all zeros after offs
 */

static void _PD_insert_field(in_long, nb, out, offs, l_order, l_bytes)
   long in_long;
   int nb;
   char *out;
   int offs, l_order, l_bytes;
   {int mi, n, dm;
    long longmask;
    static int MaxBits = 8*sizeof(long);
    unsigned char fb;
    char *in;

    in = (char *) &in_long;

/* if the output start bit is not in the first byte move past the apropriate
 * number of bytes so that the start bit is in the first byte
 */
    if (offs > 7)
       {out  += (offs >> 3);
        offs %= 8;};
        
/* if mi is less than offs, copy the first dm bits over, reset offs to 0,
 * advance mi by dm, and handle the rest as if mi >= offs
 */
    mi = MaxBits - nb;
    if (mi < offs)
       {dm = MaxBits - (8 - offs);
        if (nb == MaxBits)
           longmask = ~((1L << dm) - 1L);
        else
           longmask = ((1L << nb) - 1L) ^ ((1L << dm) - 1L);

        fb = ((in_long & longmask) >> dm) & ((1L << (nb - dm)) - 1L);
        *(out++) |= fb;

        mi  += 8 - offs;
        offs = 0;};

/* assuming mi >= offs, left shift the input so that it is bit aligned
 * with the output
 */
    dm = mi - offs;
    longmask = ~((1L << dm) - 1L);
    in_long  = (in_long << dm) & longmask;

/* reorder the bytes apropriately */
    if (l_order == REVERSE_ORDER)
       _PD_btrvout(in, l_bytes, 1L);

/* copy the remaining aligned bytes over */
    for (n = (offs+nb+7)/8; n > 0; n--, *(out++) |= *(in++));

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_SET_BIT - set the bit specified as on offset from the given pointer */

static void _PD_set_bit(base, offs)
   char *base;
   int offs;
   {int nbytes, mask;

    nbytes  = offs >> 3;
    base   += nbytes;
    offs   -= 8*nbytes;  

    mask    = (1 << (7 - offs));
    *base  |= mask;

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_GET_BIT - return the bit specified as on offset
 *             - from the given pointer
 */

static int _PD_get_bit(base, offs, nby, ord)
   char *base;
   int offs, nby, *ord;
   {int nbytes, mask, n;

    n      = offs >> 3;
    nbytes = n % nby;
    n     -= nbytes;
    offs   = offs % 8;

    if (ord == NULL)
       base += (n + nbytes);
    else
       base += (n + (ord[nbytes] - 1));

    mask = (1 << (7 - offs));

    return((*base & mask) != 0);}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_REORDER - given a pointer to an array ARR with NITEMS of NBYTES each
 *             - put them in the order defined by ORD
 */

static void _PD_reorder(arr, nitems, nbytes, ord)
   char *arr;
   long nitems;
   int nbytes, *ord;
   {char local[MAXLINE];
    int j, lreorder;

    lreorder = FALSE;

    for (j = 0; j < nbytes; j++)
        if (ord[j] != (j+1))
           {lreorder = TRUE;
             break;}

    if (lreorder)
       {for (; nitems > 0; nitems--)
           {arr--;
            for (j = 0; j < nbytes; local[j] = arr[ord[j]], j++);
            arr++;
            for (j = 0; j < nbytes; *(arr++) = local[j++]);};}

    return;}

/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

/* _PD_byte_align - given an input bitstream of packed items,
 *                  return an array of the items aligned on byte
 *                  boundaries.
 */

static void _PD_byte_align(out, in, nitems, infor, inord, boffs)
   char *out;
   char *in;
   long nitems;
   long *infor;
   int *inord;
   int boffs;
   {long nbitsin, inrem;
    int chunk1, chunk2, outbytes, remainder, i;
    unsigned char *inptr, *outptr;
    unsigned char mask1, mask2;
 
    nbitsin = infor[0];

    outbytes = (nbitsin >> 3) + 1;
 
    memset(out, 0, nitems*outbytes);

/* develop logic for doing the unpack without regard to inord. */
    inptr  = (unsigned char *)in;
    outptr = (unsigned char *)out;
    inrem  = nbitsin * nitems;
    remainder = nbitsin % 8;

    chunk1 = min(8, nbitsin);
    chunk1 -= boffs;
    chunk2 =  (boffs == 0) ? 0 : 8 - chunk1;
    mask1  = (1 << chunk1) - 1;
    mask2  = (1 << chunk2) - 1;

    while (inrem)
          {for (i=0; i<outbytes-1; i++, inptr++, outptr++, inrem -= 8)
               {*outptr = ((*inptr & mask1) << chunk2) |    
                          ((*(inptr + 1)  >> chunk1) & mask2);}
           
           if (remainder <= chunk1)
              {*outptr++ = (*inptr << chunk2) & 
                           (((1 << remainder) - 1)  << (8 - remainder));
               if (remainder == chunk1) inptr++;
               chunk1 -= remainder;
               if (chunk1 == 0) chunk1 = 8;
               chunk2  = 8 - chunk1;}
            else
              {*outptr =    ((*inptr << chunk2) &
                            (((1 << chunk1) - 1) << chunk2));
               *outptr++ |= ((*(++inptr) >> chunk1) &
                            (((1 << (remainder - chunk1)) - 1) << (8 - (remainder - chunk1) - chunk1)));
               chunk1 = 8 - (remainder - chunk1);
               chunk2 = 8 - chunk1;}
           mask1 = (1 << chunk1) - 1;
           mask2 = (1 << chunk2) - 1;
           inrem -= remainder;}
    
    return;}


/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/




