/* Do not edit this file. It is produced from the corresponding .m4 source */
/*
 *  Copyright (C) 2017, Northwestern University and Argonne National Laboratory
 *  See COPYRIGHT notice in top-level directory.
 */
/* $Id$ */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* memcpy() */

#include <unistd.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h> /* uint16_t, uint32_t, uint64_t */
#elif defined(HAVE_STDINT_H)
#include <stdint.h>   /* uint16_t, uint32_t, uint64_t */
#endif
#include <assert.h>

#include <mpi.h>

#include <pnetcdf.h>
#include <pnc_debug.h>
#include <common.h>
#include <ncx.h>

/*
 * The NetCDF CDF formats define external NC data types and describe their
 * intents of use, also shown below.
 *
 *   External type   No. Bits   Intent of use
 *   -------------   --------   ---------------------------------
 *   NC_CHAR          8         text data (only non-numerical type in NetCDF)
 *   NC_BYTE          8         1-byte integer
 *   NC_SHORT        16         2-byte signed integer
 *   NC_INT          32         4-byte signed integer
 *   NC_FLOAT        32         4-byte floating point number
 *   NC_DOUBLE       64         8-byte real number in double precision
 *   NC_UBYTE         8         unsigned 1-byte integer
 *   NC_USHORT       16         unsigned 2-byte integer
 *   NC_UINT         32         unsigned 4-byte integer
 *   NC_INT64        64         signed 8-byte integer
 *   NC_UINT64       64         unsigned 8-byte integer
 *
 *
 * Datatype Mapping between in-memory types and MPI datatypes:
 *
 *   Internal type of
 *   I/O buffer argument   Example API              MPI datatype
 *   -------------------   ----------------------   -----------------
 *   char*                 ncmpi_put_var_text       MPI_CHAR
 *   signed char*          ncmpi_put_var_schar      MPI_SIGNED_CHAR
 *   unsigned char*        ncmpi_put_var_uchar      MPI_UNSIGNED_CHAR
 *   short*                ncmpi_put_var_short      MPI_SHORT
 *   unsigned short*       ncmpi_put_var_ushort     MPI_UNSIGNED_SHORT
 *   int*                  ncmpi_put_var_int        MPI_INT
 *   unsigned int*         ncmpi_put_var_uint       MPI_UNSIGNED
 *   long*                 ncmpi_put_var_long       MPI_LONG
 *   float*                ncmpi_put_var_float      MPI_FLOAT
 *   double*               ncmpi_put_var_double     MPI_DOUBLE
 *   long long*            ncmpi_put_var_longlong   MPI_LONG_LONG_INT
 *   unsigned long long*   ncmpi_put_var_ulonglong  MPI_UNSIGNED_LONG_LONG
 *
 *
 * Note NC_CHAR is the only non-numerical data type available in NetCDF realm.
 * All other external types are considered numerical, which are illegal to be
 * converted (type-casted) to and from a variable defined in NC_CHAR type. The
 * only legal APIs to read/write a variable of type NC_CHAR are "_text" APIs.
 *
 */

/*----< ncmpii_need_convert() >----------------------------------------------*/
/* netCDF specification makes a special case for type conversion between
 * uchar and NC_BYTE: do not check for range error. See
 * http://www.unidata.ucar.edu/software/netcdf/docs/data_type.html#type_conversion
 */
int
ncmpii_need_convert(int          format, /* 1, 2, or 5 (CDF format number) */
                    nc_type      xtype,  /* external NC type */
                    MPI_Datatype itype)  /* internal MPI type */
{
    if (xtype == NC_CHAR) { /* NC_ECHAR is already checked before here */
        assert(itype == MPI_CHAR);
        return 0;
    }

    /* check special case in CDF-1 and 2 between uchar and NC_BYTE */
    if (format < NC_FORMAT_CDF5 &&
        xtype == NC_BYTE && itype == MPI_UNSIGNED_CHAR) return 0;

#if SIZEOF_LONG == SIZEOF_INT
    if (itype == MPI_LONG) itype = MPI_INT; /* long is 4-byte int */
#else
    if (itype == MPI_LONG) itype = MPI_LONG_LONG_INT; /* long is 8-byte int */
#endif

    return !( (xtype == NC_BYTE   && itype == MPI_SIGNED_CHAR)    ||
              (xtype == NC_SHORT  && itype == MPI_SHORT)          ||
              (xtype == NC_INT    && itype == MPI_INT)            ||
              (xtype == NC_FLOAT  && itype == MPI_FLOAT)          ||
              (xtype == NC_DOUBLE && itype == MPI_DOUBLE)         ||
              (xtype == NC_UBYTE  && itype == MPI_UNSIGNED_CHAR)  ||
              (xtype == NC_USHORT && itype == MPI_UNSIGNED_SHORT) ||
              (xtype == NC_UINT   && itype == MPI_UNSIGNED)       ||
              (xtype == NC_INT64  && itype == MPI_LONG_LONG_INT)  ||
              (xtype == NC_UINT64 && itype == MPI_UNSIGNED_LONG_LONG)
            );
}

/* Other options to in-place byte-swap
htonl() is for 4-byte swap
htons() is for 2-byte swap

#include <arpa/inet.h>
    dest[i] = htonl(dest[i]);
    dest[i] = htons(dest[i]);

Or

#include <byteswap.h>

        for (i=0; i<nelems; i++)
            dest[i] = __bswap_32(dest[i]);

*/

/*----< ncmpii_in_swapn() >--------------------------------------------------*/
/* in-place byte swap */
void
ncmpii_in_swapn(void       *buf,
                MPI_Offset  nelems,  /* number of elements in buf[] */
                int         esize)   /* byte size of each element */
{
#ifdef WORDS_BIGENDIAN
    return;
#else
    size_t i;

    if (esize <= 1 || nelems <= 0) return;  /* no need */

    if (esize == 4) { /* this is the most common case */
        uint32_t *dest = (uint32_t*) buf;
        for (i=0; i<nelems; i++) {
            uint32_t tmp;
            memcpy(&tmp, dest+i, 4);
            dest[i] =  (tmp << 24)
                    | ((tmp & 0x0000ff00) << 8)
                    | ((tmp & 0x00ff0000) >> 8)
                    |  (tmp >> 24);
        }
    }
    else if (esize == 8) {
        uint64_t *dest = (uint64_t*) buf;
        for (i=0; i<nelems; i++) {
            uint64_t tmp;
            memcpy(&tmp, dest+i, 8);
            dest[i] = ((tmp & 0x00000000000000FFULL) << 56) |
                      ((tmp & 0x000000000000FF00ULL) << 40) |
                      ((tmp & 0x0000000000FF0000ULL) << 24) |
                      ((tmp & 0x00000000FF000000ULL) <<  8) |
                      ((tmp & 0x000000FF00000000ULL) >>  8) |
                      ((tmp & 0x0000FF0000000000ULL) >> 24) |
                      ((tmp & 0x00FF000000000000ULL) >> 40) |
                      ((tmp & 0xFF00000000000000ULL) >> 56);
        }
    }
    else if (esize == 2) {
        uint16_t *dest = (uint16_t*) buf;
        for (i=0; i<nelems; i++) {
            uint16_t tmp;
            memcpy(&tmp, dest+i, 2);
            dest[i] = ((tmp & 0xff) << 8) |
                      ((tmp >> 8) & 0xff);
        }
    }
    else {
        uchar tmp, *op = (uchar*)buf;
        /* for esize is not 1, 2, or 4 */
        while (nelems-- > 0) {
            for (i=0; i<esize/2; i++) {
                tmp           = op[i];
                op[i]         = op[esize-1-i];
                op[esize-1-i] = tmp;
            }
            op += esize;
        }
    }
#endif
}


/*----< ncmpii_putn_NC_UBYTE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_UBYTE(
               void         *xp,     /* buffer of external type NC_UBYTE */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_UBYTE_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_UBYTE_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_UBYTE_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_UBYTE_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_UBYTE_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_UBYTE_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_UBYTE_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_UBYTE_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_UBYTE_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_UBYTE_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_UBYTE_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_SHORT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_SHORT(
               void         *xp,     /* buffer of external type NC_SHORT */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_SHORT_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_SHORT_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_SHORT_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_SHORT_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_SHORT_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_SHORT_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_SHORT_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_SHORT_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_SHORT_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_SHORT_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_SHORT_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_USHORT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_USHORT(
               void         *xp,     /* buffer of external type NC_USHORT */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_USHORT_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_USHORT_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_USHORT_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_USHORT_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_USHORT_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_USHORT_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_USHORT_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_USHORT_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_USHORT_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_USHORT_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_USHORT_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_INT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_INT(
               void         *xp,     /* buffer of external type NC_INT */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_INT_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_INT_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_INT_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_INT_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_INT_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_INT_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_INT_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_INT_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_INT_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_INT_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_INT_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_UINT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_UINT(
               void         *xp,     /* buffer of external type NC_UINT */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_UINT_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_UINT_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_UINT_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_UINT_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_UINT_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_UINT_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_UINT_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_UINT_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_UINT_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_UINT_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_UINT_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_FLOAT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_FLOAT(
               void         *xp,     /* buffer of external type NC_FLOAT */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_FLOAT_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_FLOAT_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_FLOAT_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_FLOAT_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_FLOAT_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_FLOAT_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_FLOAT_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_FLOAT_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_FLOAT_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_FLOAT_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_FLOAT_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_DOUBLE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_DOUBLE(
               void         *xp,     /* buffer of external type NC_DOUBLE */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_DOUBLE_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_DOUBLE_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_DOUBLE_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_DOUBLE_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_DOUBLE_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_DOUBLE_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_DOUBLE_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_DOUBLE_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_DOUBLE_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_DOUBLE_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_DOUBLE_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_INT64() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_INT64(
               void         *xp,     /* buffer of external type NC_INT64 */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_INT64_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_INT64_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_INT64_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_INT64_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_INT64_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_INT64_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_INT64_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_INT64_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_INT64_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_INT64_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_INT64_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_putn_NC_UINT64() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_UINT64(
               void         *xp,     /* buffer of external type NC_UINT64 */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_putn_NC_UINT64_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_UINT64_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_UINT64_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_UINT64_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_UINT64_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_UINT64_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_UINT64_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_UINT64_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_UINT64_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_UINT64_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_UINT64_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}


/* In CDF-2, NC_BYTE is considered a signed 1-byte integer in signed APIs, and
 * unsigned 1-byte integer in unsigned APIs. In CDF-5, NC_BYTE is always a
 * signed 1-byte integer. See
 * http://www.unidata.ucar.edu/software/netcdf/docs/data_type.html#type_conversion
 */
/*----< ncmpii_putn_NC_BYTE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_putn_NC_BYTE(int cdf_ver,/* 1,2,or 5 CDF format */
               void         *xp,     /* buffer of external type NC_BYTE */
               const void   *buf,    /* user buffer of internal type, itype */
               MPI_Offset    nelems,
               MPI_Datatype  itype,  /* internal data type (MPI_Datatype) */
               void         *fillp)  /* in internal representation */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        if (cdf_ver < 5)
            return ncmpix_putn_NC_UBYTE_uchar(&xp, nelems,(const uchar*)buf, fillp);
        else
            return ncmpix_putn_NC_BYTE_uchar(&xp, nelems, (const uchar*)     buf, fillp);
    }
    else if (itype == MPI_SIGNED_CHAR) /* This is for 1-byte integer */
        return ncmpix_putn_NC_BYTE_schar    (&xp, nelems, (const schar*)     buf, fillp);
    else if (itype == MPI_SHORT)
        return ncmpix_putn_NC_BYTE_short    (&xp, nelems, (const short*)     buf, fillp);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_putn_NC_BYTE_ushort   (&xp, nelems, (const ushort*)    buf, fillp);
    else if (itype == MPI_INT)
        return ncmpix_putn_NC_BYTE_int      (&xp, nelems, (const int*)       buf, fillp);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_putn_NC_BYTE_uint     (&xp, nelems, (const uint*)      buf, fillp);
    else if (itype == MPI_LONG)
        return ncmpix_putn_NC_BYTE_long     (&xp, nelems, (const long*)      buf, fillp);
    else if (itype == MPI_FLOAT)
        return ncmpix_putn_NC_BYTE_float    (&xp, nelems, (const float*)     buf, fillp);
    else if (itype == MPI_DOUBLE)
        return ncmpix_putn_NC_BYTE_double   (&xp, nelems, (const double*)    buf, fillp);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_putn_NC_BYTE_longlong (&xp, nelems, (const longlong*)  buf, fillp);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_putn_NC_BYTE_ulonglong(&xp, nelems, (const ulonglong*) buf, fillp);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}




/*----< ncmpii_getn_NC_UBYTE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_UBYTE(
        const void   *xp,     /* buffer of external type NC_UBYTE */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_UBYTE_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_UBYTE_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_UBYTE_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_UBYTE_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_UBYTE_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_UBYTE_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_UBYTE_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_UBYTE_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_UBYTE_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_UBYTE_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_UBYTE_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_SHORT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_SHORT(
        const void   *xp,     /* buffer of external type NC_SHORT */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_SHORT_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_SHORT_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_SHORT_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_SHORT_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_SHORT_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_SHORT_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_SHORT_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_SHORT_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_SHORT_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_SHORT_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_SHORT_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_USHORT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_USHORT(
        const void   *xp,     /* buffer of external type NC_USHORT */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_USHORT_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_USHORT_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_USHORT_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_USHORT_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_USHORT_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_USHORT_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_USHORT_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_USHORT_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_USHORT_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_USHORT_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_USHORT_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_INT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_INT(
        const void   *xp,     /* buffer of external type NC_INT */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_INT_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_INT_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_INT_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_INT_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_INT_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_INT_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_INT_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_INT_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_INT_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_INT_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_INT_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_UINT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_UINT(
        const void   *xp,     /* buffer of external type NC_UINT */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_UINT_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_UINT_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_UINT_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_UINT_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_UINT_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_UINT_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_UINT_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_UINT_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_UINT_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_UINT_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_UINT_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_FLOAT() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_FLOAT(
        const void   *xp,     /* buffer of external type NC_FLOAT */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_FLOAT_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_FLOAT_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_FLOAT_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_FLOAT_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_FLOAT_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_FLOAT_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_FLOAT_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_FLOAT_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_FLOAT_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_FLOAT_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_FLOAT_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_DOUBLE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_DOUBLE(
        const void   *xp,     /* buffer of external type NC_DOUBLE */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_DOUBLE_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_DOUBLE_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_DOUBLE_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_DOUBLE_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_DOUBLE_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_DOUBLE_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_DOUBLE_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_DOUBLE_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_DOUBLE_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_DOUBLE_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_DOUBLE_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_INT64() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_INT64(
        const void   *xp,     /* buffer of external type NC_INT64 */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_INT64_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_INT64_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_INT64_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_INT64_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_INT64_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_INT64_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_INT64_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_INT64_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_INT64_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_INT64_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_INT64_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}

/*----< ncmpii_getn_NC_UINT64() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_UINT64(
        const void   *xp,     /* buffer of external type NC_UINT64 */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        
            return ncmpix_getn_NC_UINT64_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_UINT64_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_UINT64_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_UINT64_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_UINT64_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_UINT64_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_UINT64_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_UINT64_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_UINT64_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_UINT64_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_UINT64_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}


/* In CDF-2, NC_BYTE is considered a signed 1-byte integer in signed APIs, and
 * unsigned 1-byte integer in unsigned APIs. In CDF-5, NC_BYTE is always a
 * signed 1-byte integer. See
 * http://www.unidata.ucar.edu/software/netcdf/docs/data_type.html#type_conversion
 */
/*----< ncmpii_getn_NC_BYTE() >---------------------------------------------------*/
/* Only xtype and itype do not match and type casting is required will call
 * this subroutine.
 */
int
ncmpii_getn_NC_BYTE(int cdf_ver,/* NC_FORMAT_CDF5 etc. */
        const void   *xp,     /* buffer of external type NC_BYTE */
        void         *ip,     /* user buffer of internal type, itype */
        MPI_Offset    nelems,
        MPI_Datatype  itype)  /* internal data type (MPI_Datatype) */
{
    assert(itype != MPI_CHAR); /* ECHAR should have been checked already */

    if (itype == MPI_UNSIGNED_CHAR) {
        if (cdf_ver < 5)
            return ncmpix_getn_NC_UBYTE_uchar(&xp, nelems,(uchar*)ip);
        else
            return ncmpix_getn_NC_BYTE_uchar(&xp, nelems,      (uchar*)ip);
    }
    else if (itype == MPI_SIGNED_CHAR)
        return ncmpix_getn_NC_BYTE_schar    (&xp, nelems,      (schar*)ip);
    else if (itype == MPI_SHORT)
        return ncmpix_getn_NC_BYTE_short    (&xp, nelems,      (short*)ip);
    else if (itype == MPI_UNSIGNED_SHORT)
        return ncmpix_getn_NC_BYTE_ushort   (&xp, nelems,     (ushort*)ip);
    else if (itype == MPI_INT)
        return ncmpix_getn_NC_BYTE_int      (&xp, nelems,        (int*)ip);
    else if (itype == MPI_UNSIGNED)
        return ncmpix_getn_NC_BYTE_uint     (&xp, nelems,       (uint*)ip);
    else if (itype == MPI_LONG)
        return ncmpix_getn_NC_BYTE_long     (&xp, nelems,       (long*)ip);
    else if (itype == MPI_FLOAT)
        return ncmpix_getn_NC_BYTE_float    (&xp, nelems,      (float*)ip);
    else if (itype == MPI_DOUBLE)
        return ncmpix_getn_NC_BYTE_double   (&xp, nelems,     (double*)ip);
    else if (itype == MPI_LONG_LONG_INT)
        return ncmpix_getn_NC_BYTE_longlong (&xp, nelems,   (longlong*)ip);
    else if (itype == MPI_UNSIGNED_LONG_LONG)
        return ncmpix_getn_NC_BYTE_ulonglong(&xp, nelems,  (ulonglong*)ip);
    DEBUG_RETURN_ERROR(NC_EBADTYPE)
}


#if 0
/*----< ncmpii_put_cast_swap() >---------------------------------------------*/
/* This subroutine type-casts and byte-swaps ibuf (in the internal data
 * representation) into xbuf (in the external data representation), if
 * necessary. xbuf is set to ibuf only if type-casting is not required (i.e.
 * data types of itype and xtype match) or the put size is bigger than
 * NC_BYTE_SWAP_BUFFER_SIZE when byte-swap is required. In this case, ibuf is
 * byte-swapped in-place if running on a little Endian machine. Otherwise,
 * xbuf is malloc-ed first and type-casted and byte-swapped into xbuf.
 */
int
ncmpii_put_cast_swap(int            format, /* NC_FORMAT_CDF2/NC_FORMAT_CDF5 */
                     MPI_Offset     nelems,   /* number of data elements */
                     nc_type        xtype,    /* external data type */
                     MPI_Datatype   itype,    /* internal data type */
                     void          *fillp,    /* pointer to fill value */
                     void          *ibuf,     /* buffer in internal type */
                     int            isNewBuf, /* whether ibuf != user buf */
                     void         **xbuf)     /* OUT: buffer in external type */
{
    int err=NC_NOERR, xsz=0, need_cast, need_swap;
    size_t nbytes;

    /* check if type casting and Endianness byte swap are needed */
    need_cast = ncmpii_need_convert(format, xtype, itype);
    need_swap = NEED_BYTE_SWAP(xtype, itype);

    ncmpii_xlen_nc_type(xtype, &xsz);
    nbytes = (size_t)(nelems * xsz);

    /* allocate xbuf if necessary */
    if (need_cast
#ifndef ENABLE_IN_PLACE_SWAP
        || (need_swap && !isNewBuf
#ifndef DISABLE_IN_PLACE_SWAP
            && nbytes <= NC_BYTE_SWAP_BUFFER_SIZE
#endif
           )
#endif
        ) {
        *xbuf = NCI_Malloc(nbytes);
        if (*xbuf == NULL) DEBUG_RETURN_ERROR(NC_ENOMEM)
    }
    else
        *xbuf = ibuf;

    /* pack ibuf to xbuf. The contents of xbuf will be in the external
     * representation, ready to be written to file.
     */
    if (need_cast) { /* user buf type mismatches NC var type */
        /* datatype conversion + byte-swap from ibuf to xbuf */
        switch(xtype) {
            case NC_BYTE:
                err = ncmpii_putn_NC_BYTE(format,*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_UBYTE:
                err = ncmpii_putn_NC_UBYTE      (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_SHORT:
                err = ncmpii_putn_NC_SHORT      (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_USHORT:
                err = ncmpii_putn_NC_USHORT     (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_INT:
                err = ncmpii_putn_NC_INT        (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_UINT:
                err = ncmpii_putn_NC_UINT       (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_FLOAT:
                err = ncmpii_putn_NC_FLOAT      (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_DOUBLE:
                err = ncmpii_putn_NC_DOUBLE     (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_INT64:
                err = ncmpii_putn_NC_INT64      (*xbuf,ibuf,nelems,itype,fillp);
                break;
            case NC_UINT64:
                err = ncmpii_putn_NC_UINT64     (*xbuf,ibuf,nelems,itype,fillp);
                break;
            default:
                DEBUG_ASSIGN_ERROR(err, NC_EBADTYPE)
                break;
        }

        /* NC_ERANGE can be caused by some elements in ibuf that is out of
         * range of the external data type, it is not considered a fatal error
         * and the request must continue to finish.
         */
        if (err != NC_NOERR && err != NC_ERANGE) {
            NCI_Free(*xbuf);
            *xbuf = NULL;
            return err;
        }
    }
    else if (need_swap) { /* no casting, just byte swap */
        if (*xbuf != ibuf) memcpy(*xbuf, ibuf, nbytes);

        /* perform array in-place byte-swap on xbuf */
        ncmpii_in_swapn(*xbuf, nelems, xsz);
    }
    return err;
}

/*----< ncmpii_get_cast_swap() >---------------------------------------------*/
/* type casting and Endianness byte swap if needed */
int
ncmpii_get_cast_swap(int            format, /* NC_FORMAT_CDF2/NC_FORMAT_CDF5 */
                     MPI_Offset     nelems, /* number of data elements */
                     nc_type        xtype,  /* external data type */
                     MPI_Datatype   itype,  /* internal data type */
                     void          *buf,    /* user buffer */
                     void          *xbuf,   /* buffer in external type */
                     void         **ibuf)   /* OUT: buffer in internal type */
{
    /* xbuf contains the data read from file and in external data type */
    int err=NC_NOERR, mpireturn, xsz=0;
    size_t nbytes;

    mpireturn = MPI_Type_size(itype, &xsz);
    if (mpireturn != MPI_SUCCESS)
        return ncmpii_error_mpi2nc(mpireturn, "MPI_Type_size");

    nbytes = (size_t)(nelems * xsz);

    if (ncmpii_need_convert(format, xtype, itype)) {
        /* user buf type mismatches NC var type */

        /* xbuf cannot be buf, but ibuf can */
        if (buf == NULL) { /* meaning ibuf cannot be buf */
            *ibuf = NCI_Malloc(nbytes);
            if (*ibuf == NULL) DEBUG_RETURN_ERROR(NC_ENOMEM)
        }
        else
            *ibuf = buf; /* both imap buftype are contiguous */

        /* type conversion + byte-swap from xbuf to ibuf */
        switch(xtype) {
            case NC_BYTE:
                err = ncmpii_getn_NC_BYTE(format,xbuf,*ibuf,nelems,itype);
                break;
            case NC_UBYTE:
                err = ncmpii_getn_NC_UBYTE      (xbuf,*ibuf,nelems,itype);
                break;
            case NC_SHORT:
                err = ncmpii_getn_NC_SHORT      (xbuf,*ibuf,nelems,itype);
                break;
            case NC_USHORT:
                err = ncmpii_getn_NC_USHORT     (xbuf,*ibuf,nelems,itype);
                break;
            case NC_INT:
                err = ncmpii_getn_NC_INT        (xbuf,*ibuf,nelems,itype);
                break;
            case NC_UINT:
                err = ncmpii_getn_NC_UINT       (xbuf,*ibuf,nelems,itype);
                break;
            case NC_FLOAT:
                err = ncmpii_getn_NC_FLOAT      (xbuf,*ibuf,nelems,itype);
                break;
            case NC_DOUBLE:
                err = ncmpii_getn_NC_DOUBLE     (xbuf,*ibuf,nelems,itype);
                break;
            case NC_INT64:
                err = ncmpii_getn_NC_INT64      (xbuf,*ibuf,nelems,itype);
                break;
            case NC_UINT64:
                err = ncmpii_getn_NC_UINT64     (xbuf,*ibuf,nelems,itype);
                break;
            default:
                DEBUG_ASSIGN_ERROR(err, NC_EBADTYPE)
                break;
        }
        /* NC_ERANGE can be caused by some elements in xbuf that is out of
         * range of the internal data type, it is not considered a fatal error
         * and the request must continue to finish.
         */
        if (err != NC_NOERR && err != NC_ERANGE) {
            if (*ibuf != buf) NCI_Free(*ibuf);
            *ibuf = NULL;
            return err;
        }
    }
    else { /* no need to convert */
        if (NEED_BYTE_SWAP(xtype, itype)) /* check if need byte swap */
            ncmpii_in_swapn(xbuf, nelems, xsz);
        *ibuf = xbuf;
    }

    return err;
}
#endif
