Logo Search packages:      
Sourcecode: labplot version File versions

putget.c

/* Do not edit this file. It is produced from the corresponding .m4 source */
/*
 *    Copyright 1996, University Corporation for Atmospheric Research
 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
 */
/* $Id: putget.m4,v 2.47 1998/10/02 17:13:11 davis Exp $ */

#include "nc.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "ncx.h"
#include "fbits.h"
#include "onstack.h"
#ifdef LOCKNUMREC
#  include <mpp/shmem.h>      /* for SGI/Cray SHMEM routines */
#  ifdef LN_TEST
#    include <stdio.h>
#  endif
#endif

#undef MIN  /* system may define MIN somewhere and complain */
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))

/* #define ODEBUG 1 */

#if ODEBUG
#include <stdio.h>
/*
 * Print the values of an array of size_t
 */
void
arrayp(const char *label, size_t count, const size_t *array)
{
      (void) fprintf(stderr, "%s", label);
      (void) fputc('\t',stderr);    
      for(; count > 0; count--, array++)
            (void) fprintf(stderr," %lu", (unsigned long)*array);
      (void) fputc('\n',stderr);    
}
#endif /* ODEBUG */


/* Begin fill */
/*
 * This is tunable parameter.
 * It essentially controls the tradeoff between the number of times
 * memcpy() gets called to copy the external data to fill 
 * a large buffer vs the number of times its called to
 * prepare the external data.
 */
#define NFILL 16



/*
 * Next 6 type specific functions
 * Fill a some memory with the default special value.
 * Formerly
NC_arrayfill()
 */
static int
NC_fill_schar(
      void **xpp,
      size_t nelems)    /* how many */
{
      schar fillp[NFILL * sizeof(double)/X_SIZEOF_CHAR];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            schar *vp = fillp;      /* lower bound of area to be filled */
            const schar *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_BYTE;
            }
      }
      return ncx_putn_schar_schar(xpp, nelems, fillp);
}

static int
NC_fill_char(
      void **xpp,
      size_t nelems)    /* how many */
{
      char fillp[NFILL * sizeof(double)/X_SIZEOF_CHAR];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            char *vp = fillp; /* lower bound of area to be filled */
            const char *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_CHAR;
            }
      }
      return ncx_putn_char_char(xpp, nelems, fillp);
}

static int
NC_fill_short(
      void **xpp,
      size_t nelems)    /* how many */
{
      short fillp[NFILL * sizeof(double)/X_SIZEOF_SHORT];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            short *vp = fillp;      /* lower bound of area to be filled */
            const short *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_SHORT;
            }
      }
      return ncx_putn_short_short(xpp, nelems, fillp);
}


#if (SIZEOF_INT >= X_SIZEOF_INT)
static int
NC_fill_int(
      void **xpp,
      size_t nelems)    /* how many */
{
      int fillp[NFILL * sizeof(double)/X_SIZEOF_INT];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            int *vp = fillp;  /* lower bound of area to be filled */
            const int *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_INT;
            }
      }
      return ncx_putn_int_int(xpp, nelems, fillp);
}

#elif SIZEOF_LONG == X_SIZEOF_INT
static int
NC_fill_int(
      void **xpp,
      size_t nelems)    /* how many */
{
      long fillp[NFILL * sizeof(double)/X_SIZEOF_INT];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            long *vp = fillp; /* lower bound of area to be filled */
            const long *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_INT;
            }
      }
      return ncx_putn_int_long(xpp, nelems, fillp);
}

#else
#error "NC_fill_int implementation"
#endif

static int
NC_fill_float(
      void **xpp,
      size_t nelems)    /* how many */
{
      float fillp[NFILL * sizeof(double)/X_SIZEOF_FLOAT];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            float *vp = fillp;      /* lower bound of area to be filled */
            const float *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_FLOAT;
            }
      }
      return ncx_putn_float_float(xpp, nelems, fillp);
}

static int
NC_fill_double(
      void **xpp,
      size_t nelems)    /* how many */
{
      double fillp[NFILL * sizeof(double)/X_SIZEOF_DOUBLE];

      assert(nelems <= sizeof(fillp)/sizeof(fillp[0]));

      {
            double *vp = fillp;     /* lower bound of area to be filled */
            const double *const end = vp + nelems;
            while(vp < end)
            {
                  *vp++ = NC_FILL_DOUBLE;
            }
      }
      return ncx_putn_double_double(xpp, nelems, fillp);
}



/*
 * Fill the external space for variable 'varp' values at 'recno'
 * with the appropriate value. If 'varp' is not a record
 * variable, fill the whole thing.
 * Formerly
xdr_NC_fill()
 */
int
fill_NC_var(NC *ncp, const NC_var *varp, size_t recno)
{
      char xfillp[NFILL * X_SIZEOF_DOUBLE];
      const size_t step = varp->xsz;
      const size_t nelems = sizeof(xfillp)/step;
      const size_t xsz = varp->xsz * nelems;
      NC_attr **attrpp = NULL;
      off_t offset;
      size_t remaining = varp->len;

      void *xp;
      int status = NC_NOERR;

      /*
       * Set up fill value
       */
      attrpp = NC_findattr(&varp->attrs, _FillValue);
      if( attrpp != NULL )
      {
            /* User defined fill value */
            if( (*attrpp)->type != varp->type || (*attrpp)->nelems != 1 )
            {
                  return NC_EBADTYPE;
            }
            else
            {
                  /* Use the user defined value */
                  char *cp = xfillp;
                  const char *const end = &xfillp[sizeof(xfillp)];

                  assert(step <= (*attrpp)->xsz);

                  for( /*NADA*/; cp < end; cp += step)
                  {
                        (void) memcpy(cp, (*attrpp)->xvalue, step);
                  }
            }
      }
      else
      {
            /* use the default */
            
            assert(xsz % X_ALIGN == 0);
            assert(xsz <= sizeof(xfillp));
      
            xp = xfillp;
      
            switch(varp->type){
            case NC_BYTE :
                  status = NC_fill_schar(&xp, nelems);
                  break;
            case NC_CHAR :
                  status = NC_fill_char(&xp, nelems);
                  break;
            case NC_SHORT :
                  status = NC_fill_short(&xp, nelems);
                  break;
            case NC_INT :
                  status = NC_fill_int(&xp, nelems);
                  break;
            case NC_FLOAT :
                  status = NC_fill_float(&xp, nelems);
                  break;
            case NC_DOUBLE : 
                  status = NC_fill_double(&xp, nelems);
                  break;
            default :
                  assert("fill_NC_var invalid type" == 0);
                  status = NC_EBADTYPE;
                  break;
            }
            if(status != NC_NOERR)
                  return status;
      
            assert(xp == xfillp + xsz);
      }

      /*
       * copyout:
       * xfillp now contains 'nelems' elements of the fill value
       * in external representation.
       */

      /*
       * Copy it out.
       */

      offset = varp->begin;
      if(IS_RECVAR(varp))
      {
            offset += (off_t)ncp->recsize * recno;
      }

      assert(remaining > 0);
      for(;;)
      {
            const size_t chunksz = MIN(remaining, ncp->chunk);
            size_t ii;
            assert(chunksz % X_ALIGN == 0);

            status = ncp->nciop->get(ncp->nciop, offset, chunksz,
                         RGN_WRITE, &xp); 
            if(status != NC_NOERR)
            {
                  return status;
            }

            /*
             * fill the chunksz buffer in units  of xsz
             */
            for(ii = 0; ii < chunksz/xsz; ii++)
            {
                  (void) memcpy(xp, xfillp, xsz);
                  xp = (char *)xp + xsz;
            }
            /*
             * Deal with any remainder
             */
            {
                  const size_t rem = chunksz % xsz;
                  if(rem != 0)
                  {
                        (void) memcpy(xp, xfillp, rem);
                        /* xp = (char *)xp + xsz; */
                  }

            }

            status = ncp->nciop->rel(ncp->nciop, offset, RGN_MODIFIED);

            if(status != NC_NOERR)
            {
                  break;
            }

            remaining -= chunksz;
            if(remaining == 0)
                  break;      /* normal loop exit */
            offset += chunksz;

      }

      return status;
}
/* End fill */


/*
 * Add a record containing the fill values.
 */
static int
NCfillrecord(NC *ncp, const NC_var *const *varpp, size_t recno)
{
      size_t ii = 0;
      for(; ii < ncp->vars.nelems; ii++, varpp++)
      {
            if( !IS_RECVAR(*varpp) )
            {
                  continue;   /* skip non-record variables */
            }
            {
            const int status = fill_NC_var(ncp, *varpp, recno);
            if(status != NC_NOERR)
                  return status;
            }
      }
      return NC_NOERR;
}

/*
 * It is advantageous to
 * #define TOUCH_LAST
 * when using memory mapped io.
 */
#if TOUCH_LAST
/*
 * Grow the file to a size which can contain recno
 */
static int
NCtouchlast(NC *ncp, const NC_var *const *varpp, size_t recno)
{
      int status = NC_NOERR;
      const NC_var *varp = NULL;
      
      {
      size_t ii = 0;
      for(; ii < ncp->vars.nelems; ii++, varpp++)
      {
            if( !IS_RECVAR(*varpp) )
            {
                  continue;   /* skip non-record variables */
            }
            varp = *varpp;
      }
      }
      assert(varp != NULL);
      assert( IS_RECVAR(varp) );
      {
            const off_t offset = varp->begin
                        + (off_t)(recno-1) * (off_t)ncp->recsize
                        + (off_t)(varp->len - varp->xsz);
            void *xp;


            status = ncp->nciop->get(ncp->nciop, offset, varp->xsz,
                         RGN_WRITE, &xp); 
            if(status != NC_NOERR)
                  return status;
            (void)memset(xp, 0, varp->xsz);
            status = ncp->nciop->rel(ncp->nciop, offset, RGN_MODIFIED);
      }
      return status;
}
#endif /* TOUCH_LAST */


/*
 * Ensure that the netcdf file has 'numrecs' records,
 * add records and fill as neccessary.
 */
static int
NCvnrecs(NC *ncp, size_t numrecs)
{
      int status = NC_NOERR;
#ifdef LOCKNUMREC
      ushmem_t myticket = 0, nowserving = 0;
      ushmem_t numpe = (ushmem_t) _num_pes();

      /* get ticket and wait */
      myticket = shmem_short_finc((shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
            ncp->lock[LOCKNUMREC_BASEPE]);
#ifdef LN_TEST
            fprintf(stderr,"%d of %d : ticket = %hu\n",
                  _my_pe(), _num_pes(), myticket);
#endif
      do {
            shmem_short_get((shmem_t *) &nowserving,
                  (shmem_t *) ncp->lock + LOCKNUMREC_SERVING, 1,
                  ncp->lock[LOCKNUMREC_BASEPE]);
#ifdef LN_TEST
            fprintf(stderr,"%d of %d : serving = %hu\n",
                  _my_pe(), _num_pes(), nowserving);
#endif
            /* work-around for non-unique tickets */
            if (nowserving > myticket && nowserving < myticket + numpe ) {
                  /* get a new ticket ... you've been bypassed */ 
                  /* and handle the unlikely wrap-around effect */
                  myticket = shmem_short_finc(
                        (shmem_t *) ncp->lock + LOCKNUMREC_LOCK,
                        ncp->lock[LOCKNUMREC_BASEPE]);
#ifdef LN_TEST
                        fprintf(stderr,"%d of %d : new ticket = %hu\n",
                              _my_pe(), _num_pes(), myticket);
#endif
            }
      } while(nowserving != myticket);
      /* now our turn to check & update value */
#endif

      if(numrecs > NC_get_numrecs(ncp))
      {


#if TOUCH_LAST
            status = NCtouchlast(ncp,
                  (const NC_var *const*)ncp->vars.value,
                  numrecs);
            if(status != NC_NOERR)
                  goto common_return;
#endif /* TOUCH_LAST */

            set_NC_ndirty(ncp);

            if(!NC_dofill(ncp))
            {
                  /* Simply set the new numrecs value */
                  NC_set_numrecs(ncp, numrecs);
            }
            else
            {
                  /* Fill each record out to numrecs */
                  size_t cur_nrecs;
                  while((cur_nrecs = NC_get_numrecs(ncp)) < numrecs)
                  {
                        status = NCfillrecord(ncp,
                              (const NC_var *const*)ncp->vars.value,
                              cur_nrecs);
                        if(status != NC_NOERR)
                        {
                              break;
                        }
                        NC_increase_numrecs(ncp, cur_nrecs +1);
                  }
                  if(status != NC_NOERR)
                        goto common_return;
            }

            if(NC_doNsync(ncp))
            {
                  status = write_numrecs(ncp);
            }

      }
common_return:
#ifdef LOCKNUMREC
      /* finished with our lock - increment serving number */
      (void) shmem_short_finc((shmem_t *) ncp->lock + LOCKNUMREC_SERVING,
            ncp->lock[LOCKNUMREC_BASEPE]);
#endif
      return status;
}


/* 
 * Check whether 'coord' values are valid for the variable.
 */
static int
NCcoordck(NC *ncp, const NC_var *varp, const size_t *coord)
{
      const size_t *ip;
      size_t *up;

      if(varp->ndims == 0)
            return NC_NOERR;  /* 'scalar' variable */

      if(IS_RECVAR(varp))
      {
            if(*coord > X_INT_MAX)
                  return NC_EINVALCOORDS; /* sanity check */
            if(NC_readonly(ncp) && *coord >= NC_get_numrecs(ncp))
            {
                  if(!NC_doNsync(ncp))
                        return NC_EINVALCOORDS;
                  /* else */
                  {
                        /* Update from disk and check again */
                        const int status = read_numrecs(ncp);
                        if(status != NC_NOERR)
                              return status;
                        if(*coord >= NC_get_numrecs(ncp))
                              return NC_EINVALCOORDS;
                  }
            }
            ip = coord + 1;
            up = varp->shape + 1;
      }
      else
      {
            ip = coord;
            up = varp->shape;
      }
      
#ifdef CDEBUG
fprintf(stderr,"  NCcoordck: coord %ld, count %d, ip %ld\n",
            coord, varp->ndims, ip );
#endif /* CDEBUG */

      for(; ip < coord + varp->ndims; ip++, up++)
      {

#ifdef CDEBUG
fprintf(stderr,"  NCcoordck: ip %p, *ip %ld, up %p, *up %lu\n",
                  ip, *ip, up, *up );
#endif /* CDEBUG */

            /* cast needed for braindead systems with signed size_t */
            if((unsigned long) *ip >= (unsigned long) *up )
                  return NC_EINVALCOORDS;
      }

      return NC_NOERR;
}


/* 
 * Check whether 'edges' are valid for the variable and 'start'
 */
/*ARGSUSED*/
static int
NCedgeck(const NC *ncp, const NC_var *varp,
       const size_t *start, const size_t *edges)
{
      const size_t *const end = start + varp->ndims;
      const size_t *shp = varp->shape;

      if(varp->ndims == 0)
            return NC_NOERR;  /* 'scalar' variable */

      if(IS_RECVAR(varp))
      {
            start++;
            edges++;
            shp++;
      }

      for(; start < end; start++, edges++, shp++)
      {
            /* cast needed for braindead systems with signed size_t */
            if((unsigned long) *edges > *shp ||
                  (unsigned long) *start + (unsigned long) *edges > *shp)
            {
                  return(NC_EEDGE);
            }
      }
      return NC_NOERR;
}


/* 
 * Translate the (variable, coord) pair into a seek index
 */
static off_t
NC_varoffset(const NC *ncp, const NC_var *varp, const size_t *coord)
{
      if(varp->ndims == 0) /* 'scalar' variable */
            return varp->begin;

      if(varp->ndims == 1)
      {
            if(IS_RECVAR(varp))
                  return varp->begin +
                         (off_t)(*coord) * (off_t)ncp->recsize;
            /* else */
            return varp->begin + (off_t)(*coord) * (off_t)varp->xsz;
      }
      /* else */
      {
            off_t lcoord = (off_t)coord[varp->ndims -1];

            size_t *up = varp->dsizes +1;
            const size_t *ip = coord;
            const size_t *const end = varp->dsizes + varp->ndims;
            
            if(IS_RECVAR(varp))
                  up++, ip++;

            for(; up < end; up++, ip++)
                  lcoord += *up * *ip;

            lcoord *= varp->xsz;
            
            if(IS_RECVAR(varp))
                  lcoord += (off_t)(*coord) * ncp->recsize;
            
            lcoord += varp->begin;
            return lcoord;
      }
}



static int
putNCvx_char_char(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const char *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_char_char(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}


static int
putNCvx_schar_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_schar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_uchar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_short(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_int(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_long(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_float(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_schar_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_schar_double(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}


static int
putNCvx_short_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_schar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_uchar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_short(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_int(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_long(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_float(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_short_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_short_double(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}


static int
putNCvx_int_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_schar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_uchar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_short(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_int(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_long(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_float(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_int_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_int_double(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}


static int
putNCvx_float_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_schar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_uchar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_short(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_int(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_long(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_float(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_float_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_float_double(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}


static int
putNCvx_double_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_schar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_uchar(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_short(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_int(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_long(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_float(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}

static int
putNCvx_double_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nput = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         RGN_WRITE, &xp); 
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_putn_double_double(&xp, nput, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
            {
                  /* not fatal to the loop */
                  status = lstatus;
            }

            (void) ncp->nciop->rel(ncp->nciop, offset,
                         RGN_MODIFIED);   

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nput;

      }

      return status;
}




static int
putNCv_text(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const char *value)
{
      if(varp->type != NC_CHAR)
            return NC_ECHAR;
      return putNCvx_char_char(ncp, varp, start, nelems, value);
}

static int
putNCv_schar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const schar *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_schar(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_schar(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_schar(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_schar(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_schar(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_uchar(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const uchar *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_uchar(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_uchar(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_uchar(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_uchar(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_uchar(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_short(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const short *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_short(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_short(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_short(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_short(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_short(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_int(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const int *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_int(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_int(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_int(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_int(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_int(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_long(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const long *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_long(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_long(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_long(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_long(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_long(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_float(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const float *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_float(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_float(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_float(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_float(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_float(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
putNCv_double(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const double *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return putNCvx_schar_double(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return putNCvx_short_double(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return putNCvx_int_double(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return putNCvx_float_double(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return putNCvx_double_double(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}




static int
getNCvx_char_char(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, char *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_char_char(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}


static int
getNCvx_schar_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_schar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_uchar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_short(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_int(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_long(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_float(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_schar_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_schar_double(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}


static int
getNCvx_short_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_schar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_uchar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_short(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_int(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_long(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_float(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_short_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_short_double(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}


static int
getNCvx_int_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_schar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_uchar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_short(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_int(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_long(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_float(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_int_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_int_double(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}


static int
getNCvx_float_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_schar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_uchar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_short(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_int(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_long(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_float(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_float_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_float_double(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}


static int
getNCvx_double_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_schar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_uchar(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_short(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_int(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_long(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_float(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}

static int
getNCvx_double_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      off_t offset = NC_varoffset(ncp, varp, start);
      size_t remaining = varp->xsz * nelems;
      int status = NC_NOERR;
      const void *xp;

      if(nelems == 0)
            return NC_NOERR;

      assert(value != NULL);

      for(;;)
      {
            size_t extent = MIN(remaining, ncp->chunk);
            size_t nget = ncx_howmany(varp->type, extent);

            int lstatus = ncp->nciop->get(ncp->nciop, offset, extent,
                         0, (void **)&xp);      /* cast away const */
            if(lstatus != NC_NOERR)
                  return lstatus;
            
            lstatus = ncx_getn_double_double(&xp, nget, value);
            if(lstatus != NC_NOERR && status == NC_NOERR)
                  status = lstatus;

            (void) ncp->nciop->rel(ncp->nciop, offset, 0);  

            remaining -= extent;
            if(remaining == 0)
                  break; /* normal loop exit */
            offset += extent;
            value += nget;
      }

      return status;
}




static int
getNCv_schar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, schar *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_schar(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_schar(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_schar(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_schar(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_schar(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_uchar(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, uchar *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_uchar(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_uchar(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_uchar(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_uchar(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_uchar(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_short(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, short *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_short(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_short(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_short(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_short(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_short(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_int(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, int *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_int(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_int(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_int(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_int(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_int(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_long(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, long *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_long(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_long(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_long(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_long(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_long(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_float(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, float *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_float(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_float(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_float(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_float(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_float(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}

static int
getNCv_double(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, double *value)
{
      switch(varp->type){
      case NC_CHAR:
            return NC_ECHAR;
      case NC_BYTE:
            return getNCvx_schar_double(ncp, varp, start, nelems,
                  value);
      case NC_SHORT:
            return getNCvx_short_double(ncp, varp, start, nelems,
                  value);
      case NC_INT:
            return getNCvx_int_double(ncp, varp, start, nelems,
                  value);
      case NC_FLOAT:
            return getNCvx_float_double(ncp, varp, start, nelems,
                  value);
      case NC_DOUBLE: 
            return getNCvx_double_double(ncp, varp, start, nelems,
                  value);
      }
      return NC_EBADTYPE;
}



static int
getNCv_text(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, char *value)
{
      if(varp->type != NC_CHAR)
            return NC_ECHAR;
      return getNCvx_char_char(ncp, varp, start, nelems, value);
}


/*
 * Copy 'nbytes' contiguous external values
 * from ('inncp', invp', inncoord')
 * to   ('outncp', 'outvp', 'outcoord')
 * 'inncp' shouldn't be the same as 'outncp'.
 * Used only by ncvarcopy()
 */
static int
NCxvarcpy(NC *inncp, NC_var *invp, size_t *incoord,
      NC *outncp, NC_var *outvp, size_t *outcoord, size_t nbytes)
{
      int status;
      off_t inoffset = NC_varoffset(inncp, invp, incoord);
      off_t outoffset = NC_varoffset(outncp, outvp, outcoord);
      void *inxp;
      void *outxp;
      const size_t chunk = MIN(inncp->chunk, outncp->chunk);

      do {
            const size_t extent = MIN(nbytes, chunk);

            status = inncp->nciop->get(inncp->nciop, inoffset, extent,
                         0, &inxp); 
            if(status != NC_NOERR)
                  return status;

            status = outncp->nciop->get(outncp->nciop, outoffset, extent,
                         RGN_WRITE, &outxp);    
            if(status != NC_NOERR)
            {
                  (void) inncp->nciop->rel(inncp->nciop, inoffset, 0);  
                  break;
            }

            (void) memcpy(outxp, inxp, extent);

            status = outncp->nciop->rel(outncp->nciop, outoffset,
                   RGN_MODIFIED);
            (void) inncp->nciop->rel(inncp->nciop, inoffset, 0);  

            nbytes -= extent;
            if(nbytes == 0)
                  break; /* normal loop exit */
            inoffset += extent;
            outoffset += extent;
            
      } while (status == NC_NOERR);

      return status;
}


/*
 *  For ncvar{put,get},
 *  find the largest contiguous block from within 'edges'.
 *  returns the index to the left of this (which may be -1).
 *  Compute the number of contiguous elements and return
 *  that in *iocountp.
 *  The presence of "record" variables makes this routine
 *  overly subtle.
 */
static int
NCiocount(const NC *const ncp, const NC_var *const varp,
      const size_t *const edges,
      size_t *const iocountp)
{
      const size_t *edp0 = edges;
      const size_t *edp = edges + varp->ndims;
      const size_t *shp = varp->shape + varp->ndims;

      if(IS_RECVAR(varp))
      {
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only 'record' variable */
                  *iocountp = *edges;
                  return(0);
            }
            /* else */
            edp0++;
      }

      assert(edges != NULL);

      /* find max contiguous */
      while(edp > edp0)
      {
            shp--; edp--;
            if(*edp < *shp )
            {
                  const size_t *zedp = edp;
                  while(zedp >= edp0)
                  {
                        if(*zedp == 0)
                        {
                              *iocountp = 0;
                              goto done;
                        }
                        /* Tip of the hat to segmented architectures */
                        if(zedp == edp0)
                              break;
                        zedp--;
                  }
                  break;
            }
            assert(*edp == *shp);
      }

      /*
       * edp, shp reference rightmost index s.t. *(edp +1) == *(shp +1)
       *
       * Or there is only one dimension.
       * If there is only one dimension and it is 'non record' dimension,
       *    edp is &edges[0] and we will return -1.
       * If there is only one dimension and and it is a "record dimension",
       *    edp is &edges[1] (out of bounds) and we will return 0;
       */
      assert(shp >= varp->shape + varp->ndims -1 
            || *(edp +1) == *(shp +1));

      /* now accumulate max count for a single io operation */
      for(*iocountp = 1, edp0 = edp;
                  edp0 < edges + varp->ndims;
                  edp0++)
      {
            *iocountp *= *edp0;
      }

done:
      return((int)(edp - edges) - 1);
}


/*
 * Set the elements of the array 'upp' to
 * the sum of the corresponding elements of
 * 'stp' and 'edp'. 'end' should be &stp[nelems].
 */
static void
set_upper(size_t *upp, /* modified on return */
      const size_t *stp,
      const size_t *edp,
      const size_t *const end)
{
      while(upp < end) {
            *upp++ = *stp++ + *edp++;
      }
}


/*
 * The infamous and oft-discussed odometer code.
 *
 * 'start[]' is the starting coordinate.
 * 'upper[]' is the upper bound s.t. start[ii] < upper[ii].
 * 'coord[]' is the register, the current coordinate value.
 * For some ii,
 * upp == &upper[ii]
 * cdp == &coord[ii]
 * 
 * Running this routine increments *cdp.
 *
 * If after the increment, *cdp is equal to *upp
 * (and cdp is not the leftmost dimension),
 * *cdp is "zeroed" to the starting value and
 * we need to "carry", eg, increment one place to
 * the left.
 * 
 * TODO: Some architectures hate recursion?
 *    Reimplement non-recursively.
 */
static void
odo1(const size_t *const start, const size_t *const upper,
      size_t *const coord, /* modified on return */
      const size_t *upp,
      size_t *cdp)
{
      assert(coord <= cdp && cdp <= coord + NC_MAX_DIMS);
      assert(upper <= upp && upp <= upper + NC_MAX_DIMS);
      assert(upp - upper == cdp - coord);
      
      assert(*cdp <= *upp);

      (*cdp)++;
      if(cdp != coord && *cdp >= *upp)
      {
            *cdp = start[cdp - coord];
            odo1(start, upper, coord, upp -1, cdp -1);
      }
}
#ifdef _CRAYC
#pragma _CRI noinline odo1
#endif




/* Public */


int
nc_put_var1_text(int ncid, int varid, const size_t *coord,
      const char *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_text(ncp, varp, coord, 1, value);
}


int
nc_put_var1_uchar(int ncid, int varid, const size_t *coord,
      const uchar *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_uchar(ncp, varp, coord, 1, value);
}

int
nc_put_var1_schar(int ncid, int varid, const size_t *coord,
      const schar *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_schar(ncp, varp, coord, 1, value);
}

int
nc_put_var1_short(int ncid, int varid, const size_t *coord,
      const short *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_short(ncp, varp, coord, 1, value);
}

int
nc_put_var1_int(int ncid, int varid, const size_t *coord,
      const int *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_int(ncp, varp, coord, 1, value);
}

int
nc_put_var1_long(int ncid, int varid, const size_t *coord,
      const long *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_long(ncp, varp, coord, 1, value);
}

int
nc_put_var1_float(int ncid, int varid, const size_t *coord,
      const float *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_float(ncp, varp, coord, 1, value);
}

int
nc_put_var1_double(int ncid, int varid, const size_t *coord,
      const double *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *coord +1);
            if(status != NC_NOERR)
                  return status;
      }

      return putNCv_double(ncp, varp, coord, 1, value);
}



/* deprecated, used to support the 2.x interface */
int
nc_put_var1(int ncid, int varid, const size_t *coord, const void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR;

      switch(varp->type){
      case NC_CHAR:
            return nc_put_var1_text(ncid, varid, coord,
                  (const char *) value);
      case NC_BYTE:
            return nc_put_var1_schar(ncid, varid, coord,
                  (const schar *) value);
      case NC_SHORT:
            return nc_put_var1_short(ncid, varid, coord,
                  (const short *) value);
      case NC_INT:
            return nc_put_var1_int(ncid, varid, coord,
                  (const int *) value);
      case NC_FLOAT:
            return nc_put_var1_float(ncid, varid, coord,
                  (const float *) value);
      case NC_DOUBLE: 
            return nc_put_var1_double(ncid, varid, coord,
                  (const double *) value);
      }
      return NC_EBADTYPE;
}



int
nc_get_var1_text(int ncid, int varid, const size_t *coord, char *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_text(ncp, varp, coord, 1, value);
}


int
nc_get_var1_uchar(int ncid, int varid, const size_t *coord, uchar *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_uchar(ncp, varp, coord, 1, value);
}

int
nc_get_var1_schar(int ncid, int varid, const size_t *coord, schar *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_schar(ncp, varp, coord, 1, value);
}

int
nc_get_var1_short(int ncid, int varid, const size_t *coord, short *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_short(ncp, varp, coord, 1, value);
}

int
nc_get_var1_int(int ncid, int varid, const size_t *coord, int *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_int(ncp, varp, coord, 1, value);
}

int
nc_get_var1_long(int ncid, int varid, const size_t *coord, long *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_long(ncp, varp, coord, 1, value);
}

int
nc_get_var1_float(int ncid, int varid, const size_t *coord, float *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_float(ncp, varp, coord, 1, value);
}

int
nc_get_var1_double(int ncid, int varid, const size_t *coord, double *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, coord);
      if(status != NC_NOERR)
            return status;

      return getNCv_double(ncp, varp, coord, 1, value);
}


/* deprecated, used to support the 2.x interface */
int
nc_get_var1(int ncid, int varid, const size_t *coord, void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR;

      switch(varp->type){
      case NC_CHAR:
            return nc_get_var1_text(ncid, varid, coord,
                  (char *) value);
      case NC_BYTE:
            return nc_get_var1_schar(ncid, varid, coord,
                  (schar *) value);
      case NC_SHORT:
            return nc_get_var1_short(ncid, varid, coord,
                  (short *) value);
      case NC_INT:
            return nc_get_var1_int(ncid, varid, coord,
                  (int *) value);
      case NC_FLOAT:
            return nc_get_var1_float(ncid, varid, coord,
                  (float *) value);
      case NC_DOUBLE: 
            return nc_get_var1_double(ncid, varid, coord,
                  (double *) value);
      }
      return NC_EBADTYPE;
}



int
nc_put_vara_text(int ncid, int varid,
       const size_t *start, const size_t *edges, const char *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_text(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_text(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_text(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_text(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}


int
nc_put_vara_uchar(int ncid, int varid,
       const size_t *start, const size_t *edges, const uchar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_uchar(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_uchar(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_uchar(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_uchar(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_schar(int ncid, int varid,
       const size_t *start, const size_t *edges, const schar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_schar(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_schar(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_schar(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_schar(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_short(int ncid, int varid,
       const size_t *start, const size_t *edges, const short *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_short(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_short(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_short(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_short(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_int(int ncid, int varid,
       const size_t *start, const size_t *edges, const int *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_int(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_int(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_int(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_int(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_long(int ncid, int varid,
       const size_t *start, const size_t *edges, const long *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_long(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_long(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_long(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_long(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_float(int ncid, int varid,
       const size_t *start, const size_t *edges, const float *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_float(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_float(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_float(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_float(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_put_vara_double(int ncid, int varid,
       const size_t *start, const size_t *edges, const double *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( putNCv_double(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            status = NCvnrecs(ncp, *start + *edges);
            if(status != NC_NOERR)
                  return status;

            if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( putNCv_double(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( putNCv_double(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = putNCv_double(ncp, varp, coord, iocount,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}



/* deprecated, used to support the 2.x interface */
int
nc_put_vara(int ncid, int varid,
       const size_t *start, const size_t *edges, const void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      switch(varp->type){
      case NC_CHAR:
            return nc_put_vara_text(ncid, varid, start, edges,
                  (const char *) value);
      case NC_BYTE:
            return nc_put_vara_schar(ncid, varid, start, edges,
                  (const schar *) value);
      case NC_SHORT:
            return nc_put_vara_short(ncid, varid, start, edges,
                  (const short *) value);
      case NC_INT:
            return nc_put_vara_int(ncid, varid, start, edges,
                  (const int *) value);
      case NC_FLOAT:
            return nc_put_vara_float(ncid, varid, start, edges,
                  (const float *) value);
      case NC_DOUBLE: 
            return nc_put_vara_double(ncid, varid, start, edges,
                  (const double *) value);
      }
      return NC_EBADTYPE;
}



int
nc_get_vara_text(int ncid, int varid,
       const size_t *start, const size_t *edges, char *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_text(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_text(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_text(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_text(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}


int
nc_get_vara_uchar(int ncid, int varid,
       const size_t *start, const size_t *edges, uchar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_uchar(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_uchar(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_uchar(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_uchar(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_schar(int ncid, int varid,
       const size_t *start, const size_t *edges, schar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_schar(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_schar(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_schar(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_schar(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_short(int ncid, int varid,
       const size_t *start, const size_t *edges, short *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_short(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_short(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_short(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_short(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_int(int ncid, int varid,
       const size_t *start, const size_t *edges, int *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_int(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_int(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_int(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_int(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_long(int ncid, int varid,
       const size_t *start, const size_t *edges, long *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_long(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_long(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_long(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_long(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_float(int ncid, int varid,
       const size_t *start, const size_t *edges, float *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_float(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_float(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_float(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_float(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}

int
nc_get_vara_double(int ncid, int varid,
       const size_t *start, const size_t *edges, double *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;
      int ii;
      size_t iocount;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      status = NCcoordck(ncp, varp, start);
      if(status != NC_NOERR)
            return status;
      status = NCedgeck(ncp, varp, start, edges);
      if(status != NC_NOERR)
            return status;

      if(varp->ndims == 0) /* scalar variable */
      {
            return( getNCv_double(ncp, varp, start, 1, value) );
      }

      if(IS_RECVAR(varp))
      {
            if(*start + *edges > NC_get_numrecs(ncp))
                  return NC_EEDGE;
            if(varp->ndims == 1 && ncp->recsize <= varp->len)
            {
                  /* one dimensional && the only record variable  */
                  return( getNCv_double(ncp, varp, start, *edges, value) );
            }
      }

      /*
       * find max contiguous
       *   and accumulate max count for a single io operation
       */
      ii = NCiocount(ncp, varp, edges, &iocount);

      if(ii == -1)
      {
            return( getNCv_double(ncp, varp, start, iocount, value) );
      }

      assert(ii >= 0);


      { /* inline */
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      ALLOC_ONSTACK(upper, size_t, varp->ndims);
      const size_t index = ii;

      /* copy in starting indices */
      (void) memcpy(coord, start, varp->ndims * sizeof(size_t));

      /* set up in maximum indices */
      set_upper(upper, start, edges, &upper[varp->ndims]);

      /* ripple counter */
      while(*coord < *upper)
      {
            const int lstatus = getNCv_double(ncp, varp, coord, iocount,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += iocount;
            odo1(start, upper, coord, &upper[index], &coord[index]);
      }

      FREE_ONSTACK(upper);
      FREE_ONSTACK(coord);
      } /* end inline */

      return status;
}



/* deprecated, used to support the 2.x interface */
int
nc_get_vara(int ncid, int varid,
       const size_t *start, const size_t *edges, void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      switch(varp->type){
      case NC_CHAR:
            return nc_get_vara_text(ncid, varid, start, edges,
                  (char *) value);
      case NC_BYTE:
            return nc_get_vara_schar(ncid, varid, start, edges,
                  (schar *) value);
      case NC_SHORT:
            return nc_get_vara_short(ncid, varid, start, edges,
                  (short *) value);
      case NC_INT:
#if (SIZEOF_INT >= X_SIZEOF_INT)
            return nc_get_vara_int(ncid, varid, start, edges,
                  (int *) value);
#elif SIZEOF_LONG == X_SIZEOF_INT
            return nc_get_vara_long(ncid, varid, start, edges,
                  (long *) value);
#else
#error "nc_get_vara implementation"
#endif
      case NC_FLOAT:
            return nc_get_vara_float(ncid, varid, start, edges,
                  (float *) value);
      case NC_DOUBLE: 
            return nc_get_vara_double(ncid, varid, start, edges,
                  (double *) value);
      }
      return NC_EBADTYPE;
}

#if defined(__cplusplus)
/* C++ consts default to internal linkage and must be initialized */
const size_t coord_zero[NC_MAX_VAR_DIMS] = {0};
#else
static const size_t coord_zero[NC_MAX_VAR_DIMS];
#endif


int
nc_put_var_text(int ncid, int varid, const char *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_text(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_text(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_text(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_text(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}


int
nc_put_var_uchar(int ncid, int varid, const uchar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_uchar(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_uchar(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_uchar(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_uchar(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_schar(int ncid, int varid, const schar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_schar(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_schar(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_schar(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_schar(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_short(int ncid, int varid, const short *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_short(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_short(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_short(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_short(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_int(int ncid, int varid, const int *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_int(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_int(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_int(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_int(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_long(int ncid, int varid, const long *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_long(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_long(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_long(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_long(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_float(int ncid, int varid, const float *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_float(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_float(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_float(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_float(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_put_var_double(int ncid, int varid, const double *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
            return NC_EPERM;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( putNCv_double(ncp, varp, &zed, 1, value) );
      }

      if(!IS_RECVAR(varp))
      {
            return(putNCv_double(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(putNCv_double(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = putNCv_double(ncp, varp, coord, elemsPerRec,
                         value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}




int
nc_get_var_text(int ncid, int varid, char *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_text(ncp, varp, &zed, 1, value) );
      }

      if(varp->type != NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_text(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_text(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_text(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}


int
nc_get_var_uchar(int ncid, int varid, uchar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_uchar(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_uchar(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_uchar(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_uchar(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_schar(int ncid, int varid, schar *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_schar(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_schar(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_schar(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_schar(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_short(int ncid, int varid, short *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_short(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_short(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_short(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_short(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_int(int ncid, int varid, int *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_int(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_int(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_int(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_int(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_long(int ncid, int varid, long *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_long(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_long(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_long(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_long(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_float(int ncid, int varid, float *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_float(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_float(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_float(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_float(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}

int
nc_get_var_double(int ncid, int varid, double *value)
{
      int status = NC_NOERR;
      NC *ncp;
      const NC_var *varp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
            return NC_EINDEFINE;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR; /* TODO: lost NC_EGLOBAL */

      if(varp->ndims == 0) /* scalar variable */
      {
            const size_t zed = 0;
            return( getNCv_double(ncp, varp, &zed, 1, value) );
      }

      if(varp->type == NC_CHAR)
            return NC_ECHAR;


      if(!IS_RECVAR(varp))
      {
            return(getNCv_double(ncp, varp, coord_zero, *varp->dsizes, value));
      }
      /* else */

      if(varp->ndims == 1
                  && ncp->recsize <= varp->len)
      {
            /* one dimensional && the only record variable  */
            return(getNCv_double(ncp, varp, coord_zero, NC_get_numrecs(ncp),
                  value));
      }
      /* else */

      {
      ALLOC_ONSTACK(coord, size_t, varp->ndims);
      size_t elemsPerRec = 1;
      const size_t nrecs = NC_get_numrecs(ncp);
      (void) memset(coord, 0, varp->ndims * sizeof(size_t));
      /* TODO: fix dsizes to avoid this nonsense */
      if(varp->ndims > 1)
            elemsPerRec = varp->dsizes[1];
      while(*coord < nrecs)
      {
            const int lstatus = getNCv_double(ncp, varp, coord, elemsPerRec,
                        value);
            if(lstatus != NC_NOERR)
            {
                  if(lstatus != NC_ERANGE)
                  {
                        status = lstatus;
                        /* fatal for the loop */
                        break;
                  }
                  /* else NC_ERANGE, not fatal for the loop */
                  if(status == NC_NOERR)
                        status = lstatus;
            }
            value += elemsPerRec;
            (*coord)++;
      }
      FREE_ONSTACK(coord);
      } /* elemsPerRec */

      return status;
}



/* Begin putgetg.c */



int
nc_get_vars_text (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      char *value)
{
      return nc_get_varm_text (ncid, varid, start, edges,
                   stride, 0, value);
}


int
nc_get_vars_uchar (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      uchar *value)
{
      return nc_get_varm_uchar (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_schar (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      schar *value)
{
      return nc_get_varm_schar (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_short (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      short *value)
{
      return nc_get_varm_short (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_int (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      int *value)
{
      return nc_get_varm_int (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_long (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      long *value)
{
      return nc_get_varm_long (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_float (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      float *value)
{
      return nc_get_varm_float (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_get_vars_double (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      double *value)
{
      return nc_get_varm_double (ncid, varid, start, edges,
                   stride, 0, value);
}


int
nc_get_vars (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      void *value)
{
      return nc_get_varm (ncid, varid, start, edges,
                   stride, 0, value);
}



int
nc_put_vars_text (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const char *value)
{
      return nc_put_varm_text (ncid, varid, start, edges,
                   stride, 0, value);
}


int
nc_put_vars_uchar (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const uchar *value)
{
      return nc_put_varm_uchar (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_schar (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const schar *value)
{
      return nc_put_varm_schar (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_short (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const short *value)
{
      return nc_put_varm_short (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_int (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const int *value)
{
      return nc_put_varm_int (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_long (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const long *value)
{
      return nc_put_varm_long (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_float (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const float *value)
{
      return nc_put_varm_float (ncid, varid, start, edges,
                   stride, 0, value);
}

int
nc_put_vars_double (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const double *value)
{
      return nc_put_varm_double (ncid, varid, start, edges,
                   stride, 0, value);
}


int
nc_put_vars (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const void *value)
{
      return nc_put_varm (ncid, varid, start, edges,
                   stride, 0, value);
}


/*
 * Generalized hyperslab input.
 */

int
nc_get_varm_text(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      char *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_text (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_text()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_text (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}


int
nc_get_varm_uchar(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      uchar *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_uchar (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_uchar()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_uchar (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_schar(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      schar *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_schar (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_schar()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_schar (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_short(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      short *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_short (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_short()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_short (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_int(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      int *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_int (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_int()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_int (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_long(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      long *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_long (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_long()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_long (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_float(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      float *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_float (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_float()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_float (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_get_varm_double(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride,
      const ptrdiff_t *map,
      double *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return getNCv_double (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  size_t dimlen = 
                        idim == 0 && IS_RECVAR (varp)
                              ? NC_get_numrecs(ncp)
                                : varp->shape[idim];
                  if (mystart[idim] >= dimlen)
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }

                  if (mystart[idim] + myedges[idim] > dimlen)
                  {
                        status = NC_EEDGE;
                        goto done;
                  }

            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_get_vara_double()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_get_vara_double (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}


/* deprecated, used to support the 2.x interface */
int
nc_get_varm (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const ptrdiff_t * map,
      void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;
      ptrdiff_t *cvtmap = NULL;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR;

      if(map != NULL && varp->ndims != 0)
      {
            /*
             * convert map units from bytes to units of sizeof(type)
             */
            size_t ii;
            const ptrdiff_t szof = (ptrdiff_t) nctypelen(varp->type);
            cvtmap = (ptrdiff_t *)calloc(varp->ndims, sizeof(ptrdiff_t));
            if(cvtmap == NULL)
                  return NC_ENOMEM;
            for(ii = 0; ii < varp->ndims; ii++)
            {
                  if(map[ii] % szof != 0) 
                  {
                        free(cvtmap);
                        return NC_EINVAL;
                  }
                  cvtmap[ii] = map[ii] / szof;
            }
            map = cvtmap;
      }

      switch(varp->type){
      case NC_CHAR:
            status =  nc_get_varm_text(ncid, varid, start, edges,
                  stride, map,
                  (char *) value);
            break;
      case NC_BYTE:
            status = nc_get_varm_schar(ncid, varid, start, edges,
                  stride, map,
                  (schar *) value);
            break;
      case NC_SHORT:
            status = nc_get_varm_short(ncid, varid, start, edges,
                  stride, map,
                  (short *) value);
            break;
      case NC_INT:
#if (SIZEOF_INT >= X_SIZEOF_INT)
            status = nc_get_varm_int(ncid, varid, start, edges,
                  stride, map,
                  (int *) value);
#elif SIZEOF_LONG == X_SIZEOF_INT
            status = nc_get_varm_long(ncid, varid, start, edges,
                  stride, map,
                  (long *) value);
#else
#error "nc_get_varm implementation"
#endif
            break;
      case NC_FLOAT:
            status = nc_get_varm_float(ncid, varid, start, edges,
                  stride, map,
                  (float *) value);
            break;
      case NC_DOUBLE: 
            status = nc_get_varm_double(ncid, varid, start, edges,
                  stride, map,
                  (double *) value);
            break;
      default:
            status = NC_EBADTYPE;
            break;
      }

      if(cvtmap != NULL)
      {
            free(cvtmap);
      }
      return status;
}


/*
 * Generalized hyperslab output.
 */

int
nc_put_varm_text(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const char *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type != NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_text (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_text()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_text (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}


int
nc_put_varm_uchar(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const uchar *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_uchar (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_uchar()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_uchar (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_schar(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const schar *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_schar (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_schar()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_schar (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_short(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const short *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_short (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_short()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_short (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_int(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const int *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_int (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_int()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_int (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_long(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const long *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_long (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_long()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_long (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_float(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const float *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_float (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_float()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_float (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}

int
nc_put_varm_double(int ncid, int varid,
      const size_t *start, const size_t *edges,
      const ptrdiff_t *stride, const ptrdiff_t *map,
      const double *value)
{
      int status = ENOERR;
      NC *ncp;
      NC_var *varp;
      int maxidim;      /* maximum dimensional index */

      status = NC_check_id (ncid, &ncp);
      if (status != NC_NOERR)
            return status;

      if (NC_indef (ncp))
      {
            return NC_EINDEFINE;
      }

            if (NC_readonly (ncp))
                  return NC_EPERM;
      varp = NC_lookupvar (ncp, varid);
      if (varp == NULL)
            return NC_ENOTVAR;

      if(varp->type == NC_CHAR)
            return NC_ECHAR;

      maxidim = (int) varp->ndims - 1;

      if (maxidim < 0)
      {
            /*
             * The variable is a scalar; consequently,
             * there s only one thing to get and only one place to put it.
             * (Why was I called?)
             */
            return putNCv_double (ncp, varp, start, 1, value);
      }
      
      /*
       * else
       * The variable is an array.
       */
      {
            int idim;
            size_t *mystart = NULL;
            size_t *myedges;
            size_t *iocount;  /* count vector */
            size_t *stop;     /* stop indexes */
            size_t *length;   /* edge lengths in bytes */
            ptrdiff_t *mystride;
            ptrdiff_t *mymap;

            /*
             * Verify stride argument.
             */
            for (idim = 0; idim <= maxidim; ++idim)
            {
                  if (stride != NULL
                        && (stride[idim] == 0
            /* cast needed for braindead systems with signed size_t */
                        || (unsigned long) stride[idim] >= X_INT_MAX))
                  {
                        return NC_ESTRIDE;
                  }
            }

            /* assert(sizeof(ptrdiff_t) >= sizeof(size_t)); */
            mystart = (size_t *)calloc(varp->ndims * 7, sizeof(ptrdiff_t));
            if(mystart == NULL)
                  return NC_ENOMEM;
            myedges = mystart + varp->ndims;
            iocount = myedges + varp->ndims;
            stop = iocount + varp->ndims;
            length = stop + varp->ndims;
            mystride = (ptrdiff_t *)(length + varp->ndims);
            mymap = mystride + varp->ndims;

            /*
             * Initialize I/O parameters.
             */
            for (idim = maxidim; idim >= 0; --idim)
            {
                  mystart[idim] = start != NULL
                        ? start[idim]
                        : 0;

                  if (edges[idim] == 0)
                  {
                        status = NC_NOERR;      /* read/write no data */
                        goto done;
                  }

                  myedges[idim] = edges != NULL
                        ? edges[idim]
                        : idim == 0 && IS_RECVAR (varp)
                        ? NC_get_numrecs(ncp) - mystart[idim]
                        : varp->shape[idim] - mystart[idim];
                  mystride[idim] = stride != NULL
                        ? stride[idim]
                        : 1;
                  mymap[idim] = map != NULL
                        ? map[idim]
                        : idim == maxidim
                        ? 1
                        : mymap[idim + 1] * (ptrdiff_t) myedges[idim + 1];

                  iocount[idim] = 1;
                  length[idim] = mymap[idim] * myedges[idim];
                  stop[idim] = mystart[idim] + myedges[idim] * mystride[idim];
            }

            /*
             * Check start, edges
             */
            for (idim = IS_RECVAR (varp); idim < maxidim; ++idim)
            {
                  if (mystart[idim] >= varp->shape[idim])
                  {
                        status = NC_EINVALCOORDS;
                        goto done;
                  }
                  if (mystart[idim] + myedges[idim] > varp->shape[idim])
                  {
                        status = NC_EEDGE;
                        goto done;
                  }
            }
            /*
             * As an optimization, adjust I/O parameters when the fastest 
             * dimension has unity stride both externally and internally.
             * In this case, the user could have called a simpler routine
             * (i.e. ncvarnc_put_vara_double()
             */
            if (mystride[maxidim] == 1
                  && mymap[maxidim] == 1)
            {
                  iocount[maxidim] = myedges[maxidim];
                  mystride[maxidim] = (ptrdiff_t) myedges[maxidim];
                  mymap[maxidim] = (ptrdiff_t) length[maxidim];
            }

            /*
             * Perform I/O.  Exit when done.
             */
            for (;;)
            {
                  /* TODO: */
                  int lstatus = nc_put_vara_double (ncid, varid, mystart, iocount,
                                    value);
                  if (lstatus != NC_NOERR 
                        && (status == NC_NOERR || lstatus != NC_ERANGE))
                        status = lstatus;

                  /*
                   * The following code permutes through the variable s
                   * external start-index space and it s internal address
                   * space.  At the UPC, this algorithm is commonly
                   * called "odometer code".
                   */
                  idim = maxidim;
            carry:
                  value += mymap[idim];
                  mystart[idim] += mystride[idim];
                  if (mystart[idim] == stop[idim])
                  {
                        mystart[idim] = start[idim];
                        value -= length[idim];
                        if (--idim < 0)
                              break; /* normal return */
                        goto carry;
                  }
            } /* I/O loop */
      done:
            free(mystart);
      } /* variable is array */
      return status;

}



/* deprecated, used to support the 2.x interface */
int
nc_put_varm (
      int ncid,
      int varid,
      const size_t * start,
      const size_t * edges,
      const ptrdiff_t * stride,
      const ptrdiff_t * map,
      const void *value)
{
      int status;
      NC *ncp;
      const NC_var *varp;
      ptrdiff_t *cvtmap = NULL;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      varp = NC_lookupvar(ncp, varid);
      if(varp == NULL)
            return NC_ENOTVAR;

      if(map != NULL && varp->ndims != 0)
      {
            /*
             * convert map units from bytes to units of sizeof(type)
             */
            size_t ii;
            const ptrdiff_t szof = (ptrdiff_t) nctypelen(varp->type);
            cvtmap = (ptrdiff_t *)calloc(varp->ndims, sizeof(ptrdiff_t));
            if(cvtmap == NULL)
                  return NC_ENOMEM;
            for(ii = 0; ii < varp->ndims; ii++)
            {
                  if(map[ii] % szof != 0) 
                  {
                        free(cvtmap);
                        return NC_EINVAL;
                  }
                  cvtmap[ii] = map[ii] / szof;
            }
            map = cvtmap;
      }

      switch(varp->type){
      case NC_CHAR:
            status =  nc_put_varm_text(ncid, varid, start, edges,
                  stride, map,
                  (const char *) value);
            break;
      case NC_BYTE:
            status = nc_put_varm_schar(ncid, varid, start, edges,
                  stride, map,
                  (const schar *) value);
            break;
      case NC_SHORT:
            status = nc_put_varm_short(ncid, varid, start, edges,
                  stride, map,
                  (const short *) value);
            break;
      case NC_INT:
#if (SIZEOF_INT >= X_SIZEOF_INT)
            status = nc_put_varm_int(ncid, varid, start, edges,
                  stride, map,
                  (const int *) value);
#elif SIZEOF_LONG == X_SIZEOF_INT
            status = nc_put_varm_long(ncid, varid, start, edges,
                  stride, map,
                  (const long *) value);
#else
#error "nc_put_varm implementation"
#endif
            break;
      case NC_FLOAT:
            status = nc_put_varm_float(ncid, varid, start, edges,
                  stride, map,
                  (const float *) value);
            break;
      case NC_DOUBLE: 
            status = nc_put_varm_double(ncid, varid, start, edges,
                  stride, map,
                  (const double *) value);
            break;
      default:
            status = NC_EBADTYPE;
            break;
      }

      if(cvtmap != NULL)
      {
            free(cvtmap);
      }
      return status;
}


/* Begin recio, deprecated */

/*
 * input 'nelems' items of contiguous data of 'varp' at 'start'
 * N.B. this function deprecated.
 */
static int
getNCvdata(const NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, void *value)
{
      switch(varp->type){
      case NC_CHAR:
            return getNCvx_char_char(ncp, varp, start, nelems,
                  (char *) value);
      case NC_BYTE:
            return getNCvx_schar_schar(ncp, varp, start, nelems,
                  (schar *) value);
      case NC_SHORT:
            return getNCvx_short_short(ncp, varp, start, nelems,
                  (short *) value);
      case NC_INT:
#if (SIZEOF_INT >= X_SIZEOF_INT)
            return getNCvx_int_int(ncp, varp, start, nelems,
                  (int *) value);
#elif SIZEOF_LONG == X_SIZEOF_INT
            return getNCvx_int_long(ncp, varp, start, nelems,
                  (long *) value);
#else
#error "getNCvdata implementation"
#endif
      case NC_FLOAT:
            return getNCvx_float_float(ncp, varp, start, nelems,
                  (float *) value);
      case NC_DOUBLE: 
            return getNCvx_double_double(ncp, varp, start, nelems,
                  (double *) value);
      }
      return NC_EBADTYPE;
}


/*
 * output 'nelems' items of contiguous data of 'varp' at 'start'
 * N.B. this function deprecated.
 */
static int
putNCvdata(NC *ncp, const NC_var *varp,
             const size_t *start, size_t nelems, const void *value)
{
      switch(varp->type){
      case NC_CHAR:
            return putNCvx_char_char(ncp, varp, start, nelems,
                  (const char *) value);
      case NC_BYTE:
            return putNCvx_schar_schar(ncp, varp, start, nelems,
                  (const schar *) value);
      case NC_SHORT:
            return putNCvx_short_short(ncp, varp, start, nelems,
                  (const short *) value);
      case NC_INT:
#if (SIZEOF_INT >= X_SIZEOF_INT)
            return putNCvx_int_int(ncp, varp, start, nelems,
                  (const int *) value);
#elif SIZEOF_LONG == X_SIZEOF_INT
            return putNCvx_long_int(ncp, varp, start, nelems,
                  (const long *) value);
#else
#error "putNCvdata implementation"
#endif
      case NC_FLOAT:
            return putNCvx_float_float(ncp, varp, start, nelems,
                  (const float *) value);
      case NC_DOUBLE: 
            return putNCvx_double_double(ncp, varp, start, nelems,
                  (const double *) value);
      }
      return NC_EBADTYPE;
}


static size_t
NCelemsPerRec(
      const NC_var *varp)
{
      size_t nelems = 1;
      size_t jj;
      for(jj = 1; jj < varp->ndims; jj++) 
            nelems *= varp->shape[jj];
      return nelems;
}


/*
 * Retrieves the number of record variables, the record variable ids, and the
 * record size of each record variable.  If any pointer to info to be returned
 * is null, the associated information is not returned.  Returns -1 on error.
 */
int
nc_inq_rec(
      int ncid,
      size_t *nrecvars,
      int *recvarids,
      size_t *recsizes)
{
      NC *ncp;

   {
      const int status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;
   }

   {
      size_t nrvars = 0;
      size_t ii = 0;
      for(; ii < ncp->vars.nelems; ii++)
      {
            const NC_var *const varp = ncp->vars.value[ii];
            if(!IS_RECVAR(varp))
                  continue;

            if(recvarids != NULL)
                  recvarids[nrvars] = (int) ii;
            if(recsizes != NULL)
            {
                  *recsizes++ = nctypelen(varp->type)
                         * NCelemsPerRec(varp);
            }
            nrvars++;
      }

      if(nrecvars != NULL)
            *nrecvars = nrvars;
    }

      return NC_NOERR;
}


static int
NCrecput(
      NC *ncp,
      size_t recnum,
      void *const *datap)
{
      int status = NC_NOERR;
      size_t nrvars = 0;
      NC_var *varp;
      size_t ii;
      size_t iocount;
      ALLOC_ONSTACK(coord, size_t, ncp->dims.nelems);

      assert(ncp->dims.nelems != 0);

      (void) memset(coord, 0, ncp->dims.nelems * sizeof(size_t));
      coord[0] = recnum;
      for(ii = 0; ii < ncp->vars.nelems; ii++)
      {
            varp = ncp->vars.value[ii];
            if(!IS_RECVAR(varp))
                  continue;
            /* else */
            nrvars++;
            if(*datap == NULL)
            {
                  datap++;
                  continue;
            }
            /* else */
            iocount = NCelemsPerRec(varp);
            status = putNCvdata(ncp, varp, coord, iocount, *datap++);
            if(status != NC_NOERR)
                  break;
      }
      if(nrvars == 0 && status == NC_NOERR)
      {
            status = NC_ENORECVARS;
      }
            
      FREE_ONSTACK(coord);
      return status;
}


static int
NCrecget(
      NC *ncp,
      size_t recnum,
      void **datap)
{
      int status = NC_NOERR;
      size_t nrvars = 0;
      NC_var *varp;
      size_t ii;
      size_t iocount;
      ALLOC_ONSTACK(coord, size_t, ncp->dims.nelems);

      assert(ncp->dims.nelems != 0);

      (void) memset(coord, 0, ncp->dims.nelems * sizeof(size_t));
      coord[0] = recnum;
      for(ii = 0; ii < ncp->vars.nelems; ii++)
      {
            varp = ncp->vars.value[ii];
            if(!IS_RECVAR(varp))
                  continue;
            /* else */
            nrvars++;
            if(*datap == NULL)
            {
                  datap++;
                  continue;
            }
            /* else */
            iocount = NCelemsPerRec(varp);
            status = getNCvdata(ncp, varp, coord, iocount, *datap++);
            if(status != NC_NOERR)
                  break;
      }
      if(nrvars == 0 && status == NC_NOERR)
      {
            status = NC_ENORECVARS;
      }

      FREE_ONSTACK(coord);
      return status;
}


/*
 * Write one record's worth of data, except don't write to variables for which
 * the address of the data to be written is null.  Return -1 on error.
 */
int
nc_put_rec(
      int ncid,
      size_t recnum,
      void * const *datap)
{
      int status;
      NC *ncp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(ncp))
      {
            return NC_EPERM;
      }

      if(NC_indef(ncp))
      {
            return NC_EINDEFINE;
      }

      status = NCvnrecs(ncp, recnum +1);
      if(status != NC_NOERR)
            return status;

      return( NCrecput(ncp, recnum, datap) );
}


/*
 * Read one record's worth of data, except don't read from variables for which
 * the address of the data to be read is null.  Return -1 on error;
 */
int
nc_get_rec(
      int ncid,
      size_t recnum,
      void **datap)
{
      int status;
      NC *ncp;

      status = NC_check_id(ncid, &ncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_indef(ncp))
      {
            return NC_EINDEFINE;
      }

      if(recnum >= NC_get_numrecs(ncp))
      {
            return NC_EINVALCOORDS;
      }

      return( NCrecget(ncp, recnum, datap) );
}


/*
 * Copy the values of a variable from an input netCDF to an output netCDF.
 * Input and output var assummed to have the same shape.
 * return -1 on error.
 */
int
nc_copy_var(int ncid_in, int varid, int ncid_out)
{
      int status = NC_NOERR;
      NC *inncp, *outncp;
      NC_var *invp, *outvp;

      status = NC_check_id(ncid_in, &inncp); 
      if(status != NC_NOERR)
            return status;


      if(NC_indef(inncp))
      {
            return NC_EINDEFINE;
      }

      status = NC_check_id(ncid_out, &outncp); 
      if(status != NC_NOERR)
            return status;

      if(NC_readonly(outncp))
      {
            /* output file isn't writable */
            return NC_EPERM;
      }

      if(NC_indef(outncp))
      {
            return NC_EINDEFINE;
      }

      /* find the variable in the input cdf */
      invp = NC_lookupvar(inncp, varid);
      if(invp == NULL)
      {
            return NC_ENOTVAR;
      }

      /* find the variable in the output cdf */
      if(NC_findvar(&outncp->vars, invp->name->cp, &outvp) == -1)
      {
            return NC_ENOTVAR;
      }

      /* can we even attempt to copy without conversion? */
      if(outvp->type != invp->type)
      {
            return NC_EINVAL;
      }

      if(        (invp->ndims == 0 && outvp->ndims != 0)
            || (invp->ndims != 0 && outvp->ndims == 0)
            || (IS_RECVAR(invp) && !IS_RECVAR(outvp))
            || (!IS_RECVAR(invp) && IS_RECVAR(outvp))
            || (invp->len != outvp->len)
      )
      {
            return NC_EINVAL;
      }

      /*
       * Check coordinates
       */
      {
      ALLOC_ONSTACK(coord, size_t, invp->ndims);
      const size_t nrecs = NC_get_numrecs(inncp);
      (void) memcpy(coord, invp->shape, invp->ndims * sizeof(size_t));
      if(IS_RECVAR(invp))
            *coord = nrecs;
      
      {
      size_t ii = 0;
      for(; ii < invp->ndims; ii++)
            coord[ii] --;
      }
      /* at this point, coord is the largest valid coord of invp */

      if(NCcoordck(outncp, outvp, coord) != NC_NOERR)
      {
            return NC_EINVAL;
      }
      /* else */

      (void) memset(coord, 0, invp->ndims * sizeof(size_t));
      
      if(!IS_RECVAR(invp))
      {
            status = NCxvarcpy(inncp, invp, coord,
                        outncp, outvp, coord,
                        invp->len);
            goto done;
      }
      /* else */

      status = NCvnrecs(outncp, nrecs);
      if(status != NC_NOERR)
            goto done;

      for( /*NADA*/; *coord < nrecs; (*coord)++)
      {
            status = NCxvarcpy(inncp, invp, coord,
                        outncp, outvp, coord,
                        invp->len);
            if(status != NC_NOERR)
                  break;
      }
done:
      FREE_ONSTACK(coord);
      }
      return status;
}

Generated by  Doxygen 1.6.0   Back to index