/******************************************************************************

   FILE:  MC0.C

          Low level-routines for converting the various variable types
          across different machine formats.

          89-02-21 - J. Ranada
          95-02-16 - JR - modified copy_byte to make it possible to
			  do "in-place" conversions, i.e., the convert_array_*
			  routines can be called using the same address for
			  dest and buff; since copy_byte does all the work,
			  a test to see if dest == buff, and if so, to allocate
			  some temporary buffer to do the byte-swapping was
			  added.

 *****************************************************************************/
#include "common.h"   /* HOST_ENVIRONMENT */
#include "mem_.h"     /* cmp_byte() */
#include "find_def.h" /* find_def() */
#include "mc0.h"
/*---------------------------------------------------------
   BYTE-SWAPPING PATTERN FOR VAX-DFLOAT FORMAT DOUBLE TYPE
  ---------------------------------------------------------*/
int VAX_DOUBLE_INDEX[] = {1, 0, 3, 2, 5, 4, 7, 6};


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

    FUNCTION:  copy_byte

       Copies <nbytes> bytes from <src> to <dest> AS_IS, INVERTED, or
       SPECIAL, depending on the setting of <flag>.  If <flag> is set
       to SPECIAL, then the parameter <index> must point to an index array
       indicating the order of byte-swapping.

    RETURNS:  no. of bytes copied

*/
#if PROTOTYPE_ALLOWED
unsigned int copy_byte(char dest[], char src[], int nbytes, int flag, int index[])
#else
unsigned int copy_byte(dest, src, nbytes, flag, index)
char dest[], src[];
int nbytes, flag, index[];
#endif
{
   int i;
   char *buff;

   switch (flag)
   {
      case AS_IS:
         if (dest != src)
         {
            for (i = 0; i < nbytes; i++)
               dest[i] = src[i];
         }
         else
            i = nbytes;
         break;
      case INVERTED:
         if (dest == src)
            buff = malloc(nbytes);
         else
            buff = dest;
         for (i = 0; i < nbytes; i++)
            buff[i] = src[nbytes-1-i];
         if (dest != buff)
         {
            for (i = 0; i < nbytes; i++)
               dest[i] = buff[i];
            free(buff);
         }
         break;
      case SPECIAL:
         if (dest == src)
            buff = malloc(nbytes);
         else
            buff = dest;
         for (i = 0; i < nbytes; i++)
            buff[i] = src[index[i]];
         if (dest != buff)
         {
            for (i = 0; i < nbytes; i++)
               dest[i] = buff[i];
            free(buff);
         }
         break;
      default:
         i = 0;
         break;
   }
   return(i);
}

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

    FUNCTION:  shift_double

       Shifts a double-sized <orig> <nbits> to the RIGHT or LEFT depending
       on the setting of <direction>.

*/
#if PROTOTYPE_ALLOWED
void shift_double(unsigned char orig[], int nbits, int direction, int to)
#else
void shift_double(orig, nbits, direction, to)
unsigned char orig[];
int nbits, direction, to;
#endif
{
   int i;
   unsigned char c[8];
   union
   {
      unsigned short int us;
      unsigned char c[2];
   } u;
   int offset;  /* adjust for byte swapping */

   offset = !(to == PC_COMPATIBLE_HOST || to == VAXD_COMPATIBLE_HOST);
   copy_byte((char *) c, (char *) orig, 8, AS_IS, NULL);
   c[0] &= 0x7F;            /* turn sign bit off */
   u.us = 0;

   if (direction == RIGHT)
      for (i = 0; i < 8; i++)
      {
         *(u.c + offset) = c[i];
         u.us = u.us << (8 - nbits);
         c[i] = *(u.c + (1 - offset));
         u.us = u.us << nbits;
      }
   else
      for (i = 7; i >= 0; i--)
      {
         *(u.c + (1 - offset)) = c[i];
         u.us = u.us >> (8 - nbits);
         c[i] = *(u.c + offset);
         u.us = u.us >> nbits;
      }

   if (orig[0] > 0x7F)
      c[0] |= 0x80;         /* turn sign bit on */

   copy_byte((char *) orig, (char *) c, 8, AS_IS, NULL);
}

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

    FUNCTION:  IEEE_to_VAXDFLOAT

       Converts an IEEE format double <ieee> (bytes in normal order) to a
       VAX-DFLOAT format double <vaxd>.

    RETURNS:

       0 if okay
      -1 if exponent overflow

*/
#if PROTOTYPE_ALLOWED
int IEEE_to_VAXDFLOAT(unsigned char vaxd[], unsigned char ieee[])
#else
int IEEE_to_VAXDFLOAT(vaxd, ieee)
unsigned char vaxd[], ieee[];
#endif
{
   unsigned char s, t;

   s = ieee[0] & 0x80;      /* save sign bit */
   ieee[0] &= 0x7F;         /* turn off sign bit */
   if (cmp_byte( (char *) ieee, "\0\0\0\0\0\0\0\0", 8))
   {
      ieee[0] -= 0x37;
      t = ieee[1] - 0xE0;
      if (t > ieee[1])
         ieee[0] --;           /* there is a borrow */
      ieee[1] = t;
      if (ieee[0] > 0xF)
      {
         printf("\n ERROR: exponent overflow %u", ieee[0]);
         puts("\n FROM FUNCTION: IEEE_to_VAXDFLOAT");
         return(-1);
      }
      shift_double(ieee, 3, LEFT, VAXD_COMPATIBLE_HOST);
   }
   if (s != 0)
      ieee[0] |= 0x80;      /* turn on sign bit */
   copy_byte((char *) vaxd, (char *) ieee, 8, SPECIAL, VAX_DOUBLE_INDEX);
   return(0);
}

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

    FUNCTION:  VAXDFLOAT_to_IEEE

       Converts a VAX-DFLOAT format double <vaxd> to an IEEE format double
       <ieee>.

*/
#if PROTOTYPE_ALLOWED
void VAXDFLOAT_to_IEEE(unsigned char ieee[], unsigned char vaxd[], int to)
#else
void VAXDFLOAT_to_IEEE(ieee, vaxd, to)
unsigned char ieee[], vaxd[];
int to;
#endif
{
   unsigned char t;
   static unsigned char signed_zero[] = {0x80, 0, 0, 0, 0, 0, 0, 0};

   copy_byte((char *) ieee, (char *) vaxd, 8, SPECIAL, VAX_DOUBLE_INDEX);
   if ((cmp_byte((char *) vaxd, "\0\0\0\0\0\0\0\0", 8)) &&
      (cmp_byte((char *) vaxd, (char *)signed_zero, 8)))
   {
      shift_double(ieee, 3, RIGHT, to);
      ieee[0] += 0x37;        /* add bias byte-by-byte */
      t = ieee[1] + 0xE0;
      if (t < ieee[1])
         ieee[0] ++;          /* there is a carry */
      ieee[1] = t;
   }
}

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

    FUNCTION:   convert_array_double

       Copies the <src> array of <nv> doubles in <from> format to the
       <dest> array of doubles in the HOST_ENVIRONMENT format.

    RETURNS:

       no. of bytes converted if okay
       BADUINT on error (unknown host or exponent overflow)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_array_double(char dest[], char src[], int from, int to, unsigned int nv)
#else
unsigned int convert_array_double(dest, src, from, to, nv)
char dest[], src[];
int from, to;
unsigned int nv;
#endif
{
   unsigned char temp[8];
   unsigned int i;

   switch(to)
   {
      case PC_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(DOUBLE), src + i * sizeof(DOUBLE),
                     sizeof(DOUBLE), INVERTED, NULL);
               return(nv * sizeof(DOUBLE));
            case VAXD_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  VAXDFLOAT_to_IEEE(temp, (unsigned char *) src + i * sizeof(DOUBLE), to);
                  copy_byte(dest + i * sizeof(DOUBLE), (char *) temp, sizeof(DOUBLE), INVERTED,
                     NULL);
               }
               return(nv * sizeof(DOUBLE));
            case PC_COMPATIBLE_HOST:
	            return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL));
            default:
               printf("\n ERROR: unknown host = %u", from);
         }
         break;
      case SUN3_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL));
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(DOUBLE), src + i * sizeof(DOUBLE),
                     sizeof(DOUBLE), INVERTED, NULL);
               return(nv * sizeof(DOUBLE));
            case VAXD_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  VAXDFLOAT_to_IEEE(temp, (unsigned char *) src + i * sizeof(DOUBLE), to);
                  copy_byte(dest + i * sizeof(DOUBLE), (char *) temp, sizeof(DOUBLE), AS_IS,
                     NULL);
               }
               return(nv * sizeof(DOUBLE));
            default:
               printf("\n ERROR: unknown host = %u", from);
         }
         break;
      case VAXD_COMPATIBLE_HOST:
         switch(from)
         {
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  copy_byte((char *) temp, src + i * sizeof(DOUBLE), sizeof(DOUBLE),
                     INVERTED, NULL);
                  if (IEEE_to_VAXDFLOAT((unsigned char *) dest + i * sizeof(DOUBLE),
                     temp) != 0)
                  {
                     printf("\n ERROR: exponent overflow converting value i = %u", i);
                     goto error_found;
                  }
               }
               return(nv * sizeof(DOUBLE));
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  copy_byte((char *) temp, src + i * sizeof(DOUBLE), sizeof(DOUBLE),
                     AS_IS, NULL);
                  if (IEEE_to_VAXDFLOAT((unsigned char *) dest + i * sizeof(DOUBLE),
                     temp) != 0)
                  {
                     printf("\n ERROR: exponent overflow converting value i = %u", i);
                     goto error_found;
                  }
               }
               return(nv * sizeof(DOUBLE));
            case VAXD_COMPATIBLE_HOST:
	            return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL));
            default:
               printf("\n ERROR: unknown host = %u", from);
         }
         break;
      default:
         printf("\n ERROR: unknown destination = %u", to);
         break;
   }
   error_found:
      puts("\n FROM FUNCTION: convert_array_double");
      return(BADUINT);
}

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

    FUNCTION:  convert_array_float

       Copies the <src> array of <nv> floats in <from> format to the
       <dest> array of floats in HOST_ENVIRONMENT format.

    RETURNS:

       no. of bytes converted if okay
       BADUINT on error (unknown host)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_array_float(char dest[], char src[], int from, int to, unsigned int nv)
#else
unsigned int convert_array_float(dest, src, from, to, nv)
char dest[], src[];
int from, to;
unsigned int nv;
#endif
{
   unsigned int i, j;
   static unsigned char ieee_signed_zero[] = {0x80, 0, 0, 0};
   static unsigned char pc_signed_zero[] = {0, 0, 0, 0x80};
   static unsigned char vax_signed_zero[] = {0, 0x80, 0, 0};

   switch (to)
   {
      case PC_COMPATIBLE_HOST:
         switch (from)
         {
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(FLOAT), src + i * sizeof(FLOAT),
                     sizeof(FLOAT), INVERTED, NULL);
               return(nv * sizeof(FLOAT));
            case VAXD_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  j = i * sizeof(FLOAT);
                  *(dest + j)     = *(src + j + 2);
                  *(dest + j + 1) = *(src + j + 3);
                  *(dest + j + 2) = *(src + j);
                  if ((cmp_byte(src + j, "\0\0\0\0", 4)) 
                     && (cmp_byte(src + j,(char *) vax_signed_zero, 4)))
                     *(dest + j + 3) = *(src + j + 1) - 1; /* adjust for bias difference */
                  else
                     *(dest + j + 3) = *(src + j + 1);
               }
               return(nv * sizeof(FLOAT));
            case PC_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL));
            default:
               printf("\n ERROR: unknown host  = %u", from);
               puts("\n FROM FUNCTION: convert_array_float");
               return(BADUINT);
         }
         break;
      case VAXD_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  j = i * sizeof(FLOAT);
                  *(dest + j)     = *(src + j + 1);
                  if ((cmp_byte(src + j, "\0\0\0\0", 4)) &&
                     (cmp_byte(src + j, (char *)ieee_signed_zero, 4)))
                     *(dest + j + 1) = *(src + j) + 1;   /* adjust for bias difference */
                  else
                     *(dest + j + 1) = *(src + j);
                  *(dest + j + 2) = *(src + j + 3);
                  *(dest + j + 3) = *(src + j + 2);
               }
               return(nv * sizeof(FLOAT));
            case VAXD_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL));
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  j = i * sizeof(FLOAT);
                  *(dest + j)     = *(src + j + 2);
                  if ((cmp_byte(src + j, "\0\0\0\0", 4)) 
                     && (cmp_byte(src + j,(char *) pc_signed_zero, 4)))
                     *(dest + j + 1) = *(src + j + 3) + 1; /* adjust for bias difference */
                  else
                     *(dest + j + 1) = *(src + j + 3);
                  *(dest + j + 2) = *(src + j);
                  *(dest + j + 3) = *(src + j + 1);
               }
               return(nv * sizeof(FLOAT));
            default:
               printf("\n ERROR: unknown host  = %u", from);
               puts("\n FROM FUNCTION: convert_array_float");
               return(BADUINT);
         }
         break;
      case SUN3_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL));
            case VAXD_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
               {
                  j = i * sizeof(FLOAT);
                  if ((cmp_byte(src + j, "\0\0\0\0", 4)) &&
                     (cmp_byte(src + j, (char *)vax_signed_zero, 4)))
                     *(dest + j)  = *(src + j + 1) - 1; /* adjust for bias difference */
                  else
                     *(dest + j)  = *(src + j + 1);
                  *(dest + j + 1) = *(src + j);
                  *(dest + j + 2) = *(src + j + 3);
                  *(dest + j + 3) = *(src + j + 2);
               }
               return(nv * sizeof(FLOAT));
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(FLOAT), src + i * sizeof(FLOAT),
                     sizeof(FLOAT), INVERTED, NULL);
               return(nv * sizeof(FLOAT));
            default:
               printf("\n ERROR: unknown host  = %u", from);
               puts("\n FROM FUNCTION: convert_array_float");
               return(BADUINT);
         }
         break;
      default:
         printf("\n ERROR: unknown destination  = %u", to);
         puts("\n FROM FUNCTION: convert_array_float");
   }
   return(BADUINT);
}

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

    FUNCTION:  convert_array_long

       Copies the <src> array of <nv> longs/unsigned longs in <from> format
       to the <dest> array of longs/unsigned longs in HOST_ENVIRONMENT format.

    RETURNS:

       no. of bytes converted if okay
       BADUINT on error (unknown host)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_array_long(char dest[], char src[], int from, int to, unsigned int nv)
#else
unsigned int convert_array_long(dest, src, from, to, nv)
char dest[], src[];
int from, to;
unsigned int nv;
#endif
{
   unsigned int i;

   switch(to)
   {
      case PC_COMPATIBLE_HOST:
      case VAXD_COMPATIBLE_HOST:
         switch (from)
         {
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(LONG), src + i * sizeof(LONG),
                     sizeof(LONG), INVERTED, NULL);
               return(nv * sizeof(LONG));
            case VAXD_COMPATIBLE_HOST:
            case PC_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(LONG), AS_IS, NULL));
            default:
               printf("\n ERROR: unknown host = %u", from);
               puts("\n FROM FUNCTION: convert_array_long");
               return(BADUINT);
         }
         break;
      case SUN3_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(LONG), AS_IS, NULL));
            case VAXD_COMPATIBLE_HOST:
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i ++)
                  copy_byte(dest + i * sizeof(LONG), src + i * sizeof(LONG),
                     sizeof(LONG), INVERTED, NULL);
               return(nv * sizeof(LONG));
            default:
               printf("\n ERROR: unknown host = %u", from);
               puts("\n FROM FUNCTION: convert_array_long");
               return(BADUINT);
         }
         break;
      default:
         printf("\n ERROR: unknown destination = %u", to);
         puts("\n FROM FUNCTION: convert_array_long");
   }
   return(BADUINT);
}

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

    FUNCTION:  convert_array_short

       Copies the <src> array of <nv> shorts/unsigned shorts in <from>
       format to the <dest> array of shorts/unsigned shorts in
       HOST_ENVIRONMENT format.

    RETURNS:

       no. of bytes converted if okay
       BADUINT on error (unknown host)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_array_short(char dest[], char src[], int from, int to, unsigned int nv)
#else
unsigned int convert_array_short(dest, src, from, to, nv)
char dest[], src[];
int from, to;
unsigned int nv;
#endif
{
   unsigned int i;

   switch(to)
   {
      case PC_COMPATIBLE_HOST:
      case VAXD_COMPATIBLE_HOST:
         switch (from)
         {
            case SUN3_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(SHORT), src + i * sizeof(SHORT),
                     sizeof(SHORT), INVERTED, NULL);
               return(nv * sizeof(SHORT));
            case VAXD_COMPATIBLE_HOST:
            case PC_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(SHORT), AS_IS, NULL));
            default:
               printf("\n ERROR: unknown host = %u", from);
               puts("\n FROM FUNCTION: convert_array_short");
               return(BADUINT);
         }
         break;
      case SUN3_COMPATIBLE_HOST:
         switch(from)
         {
            case SUN3_COMPATIBLE_HOST:
               return(copy_byte(dest, src, nv * sizeof(SHORT), AS_IS, NULL));
            case VAXD_COMPATIBLE_HOST:
            case PC_COMPATIBLE_HOST:
               for (i = 0; i < nv; i++)
                  copy_byte(dest + i * sizeof(SHORT), src + i * sizeof(SHORT),
                     sizeof(SHORT), INVERTED, NULL);
               return(nv * sizeof(SHORT));
            default:
               printf("\n ERROR: unknown host = %u", from);
               puts("\n FROM FUNCTION: convert_array_short");
               return(BADUINT);
         }
         break;
      default:
         printf("\n ERROR: unknown destination = %u", to);
         puts("\n FROM FUNCTION: convert_array_short");
   }
   return(BADUINT);
}

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

    FUNCTION:  convert_struct

       Converts a structure <src> in <from> format to the structure
       <dest> in HOST_ENVIRONMENT format by referring to the structure
       definition specified by <struct_name> located somewhere in the
       linked list pointed to by <strdef>.

    RETURNS:

       no. of bytes converted if okay
       BADUINT if no structure definition is found

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_struct(char *dest, char *src, int from, int to, char *struct_name, STRUCT_DEF_HDR_TYPE *strdef)
#else
unsigned int convert_struct(dest, src, from, to, struct_name, strdef)
char *dest, *src, *struct_name;
int from, to;
STRUCT_DEF_HDR_TYPE *strdef;
#endif
{
   unsigned int i, nelem, byte_count, ofs = 0;
   STRUCT_DEF_ENTRY_TYPE *strdef_ptr;

   if ((strdef == NULL) || ((strdef_ptr = (STRUCT_DEF_ENTRY_TYPE *)
      find_def(struct_name, strdef)) == NULL))
   {
      printf("\n ERROR: undefined structure = %s", struct_name);
      goto error_found;
   }

   nelem = strdef_ptr->hdr.nelem;
   for (i = 0; i < nelem; i++)
   {
      strdef_ptr += 1;
      if ((byte_count = convert_select(dest + ofs, src + ofs, from, to,
                                       strdef_ptr->elem.count,
                                       strdef_ptr->elem.value_type,
                                       strdef_ptr->elem.name,
                                       strdef)) == BADUINT)
         goto error_found;
      ofs += byte_count;
   }
   return(ofs);

   error_found:
      puts("\n FROM FUNCTION: convert_struct");
      return(BADUINT);
}

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

    FUNCTION:  convert_array_struct

       Converts <nv> instances of the structure <struct-name> from <src> in
       <from> format to <dest> in HOST_ENVIRONMENT format using the
       structure definition somewhere in <strdef> as a key.

    NOTE:  If the parameter <nv> is less than zero, then its absolute value is
       taken as an indication of the number of bytes in the entire array of 
       structure, and conversion continues until all <nv> bytes have been
       processed.

    RETURNS:

       no. of bytes converted if okay
       BADUINT if error (undefined structure, unknown host or exponent overflow)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_array_struct(char *dest, char *src, 
                                 int from, int to, int nv,
                                 char *struct_name, STRUCT_DEF_HDR_TYPE *strdef)
#else
unsigned int convert_array_struct(dest, src, from, to, nv, struct_name, strdef)
char *dest, *src, *struct_name;
int from, to;
int nv;
STRUCT_DEF_HDR_TYPE *strdef;
#endif
{
   unsigned int i, ofs = 0, byte_count = 0;

   if (nv < 0)  /* -nv is no. of bytes in data structure */
   {
      while (ofs < abs(nv))
      {
         if ((byte_count = convert_struct(dest + ofs, src + ofs, from, to,
                                          struct_name, strdef)) == BADUINT)
            goto error_found;
         ofs += byte_count;
      }
      return(ofs);
   }
   for (i = 0; i < nv; i++)
   {
      if ((byte_count = convert_struct(dest + ofs, src + ofs, from, to,
                                       struct_name, strdef)) == BADUINT)
         goto error_found;
      ofs += byte_count;
   }
   return(ofs);

   error_found:
      puts("\n FROM FUNCTION: convert_array_struct");
      return(BADUINT);
}

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

    FUNCTION:  convert_select

       Copies <nv> values from <src> array in <from> format to the <dest>
       array in HOST_ENVIRONMENT format by calling the appropriate
       convert_array_* function, if needed, according to the setting of the
       <value_type> flag.  In the case of a STRUCT_VALUE_CODE <value_type>,
       additional information regarding the <struct_name> and <strdef> is
       needed.

    RETURNS:

       no. of bytes converted if okay
       BADUINT on error (undefined structure, unknown host, exponent overflow,
                         or unrecognized value type)

*/
#if PROTOTYPE_ALLOWED
unsigned int convert_select(char *dest, char *src,
			    int from, int to, 
			    unsigned int nv, unsigned int value_type, 
			    char *struct_name, STRUCT_DEF_HDR_TYPE *strdef)
#else
unsigned int convert_select(dest, src, from, to, nv, value_type, struct_name, strdef)
char *dest, *src, *struct_name;
int from, to;
unsigned int nv, value_type;
STRUCT_DEF_HDR_TYPE *strdef;
#endif
{
   switch (value_type)
   {
      case BYTE_VALUE_CODE:
      case UBYTE_VALUE_CODE:
      case CHAR_VALUE_CODE:
      case TEXT_VALUE_CODE:
         return(copy_byte(dest, src, nv, AS_IS, NULL));
      case SHORT_VALUE_CODE:
      case USHORT_VALUE_CODE:
         return(convert_array_short(dest, src, from, to, nv));
      case LONG_VALUE_CODE:
      case ULONG_VALUE_CODE:
         return(convert_array_long(dest, src, from, to, nv));
      case FLOAT_VALUE_CODE:
         return(convert_array_float(dest, src, from, to, nv));
      case DOUBLE_VALUE_CODE:
         return(convert_array_double(dest, src, from, to, nv));
      case COMPLEX_VALUE_CODE:
         return(convert_array_float(dest, src, from, to, nv * 2));
      case STRUCT_VALUE_CODE:
         return(convert_array_struct(dest, src, from, to, nv, struct_name, strdef));
      default:
         printf("\n ERROR: unrecognized value type = %d", value_type);
         puts("\n FROM FUNCTION: convert_select");
         return(BADUINT);
   }
}
