/* 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.50 2003/06/30 20:43:08 russ 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;
}
