/* Do not edit this file. It is produced from the corresponding .m4 source */
/*********************************************************************
 *   Copyright 1996, UCAR/Unidata
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
 *   $Id: test_put.m4,v 1.20 1997/05/13 22:48:21 russ Exp $
 *********************************************************************/


#include "tests.h"


/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_text(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = text_min;
    const double max = text_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_uchar(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = uchar_min;
    const double max = uchar_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_schar(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = schar_min;
    const double max = schar_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_short(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = short_min;
    const double max = short_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_int(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = int_min;
    const double max = int_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_long(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = long_min;
    const double max = long_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_float(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = float_min;
    const double max = float_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}

/*
 *  ensure hash value within range for internal TYPE
 */
double
hash_double(
    const nc_type type,
    const int rank,
    const size_t *index,
    const nct_itype itype)
{
    const double min = double_min;
    const double max = double_max;

    return MAX(min, MIN(max, hash4( type, rank, index, itype)));
}




/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_text(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    text value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_TEXT);
		err = nc_get_var1_text(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_TEXT)) {
                    if (expect >= text_min && expect <= text_max) {
			IF (err) {
			    error("nc_get_var1_text: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_TEXT)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_uchar(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    uchar value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_UCHAR);
		err = nc_get_var1_uchar(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_UCHAR)) {
                    if (expect >= uchar_min && expect <= uchar_max) {
			IF (err) {
			    error("nc_get_var1_uchar: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_UCHAR)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_schar(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    schar value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_SCHAR);
		err = nc_get_var1_schar(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_SCHAR)) {
                    if (expect >= schar_min && expect <= schar_max) {
			IF (err) {
			    error("nc_get_var1_schar: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_SCHAR)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_short(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    short value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_SHORT);
		err = nc_get_var1_short(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_SHORT)) {
                    if (expect >= short_min && expect <= short_max) {
			IF (err) {
			    error("nc_get_var1_short: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_SHORT)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_int(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    int value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_INT);
		err = nc_get_var1_int(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_INT)) {
                    if (expect >= int_min && expect <= int_max) {
			IF (err) {
			    error("nc_get_var1_int: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_INT)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_long(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    long value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_LONG);
		err = nc_get_var1_long(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_LONG)) {
                    if (expect >= long_min && expect <= long_max) {
			IF (err) {
			    error("nc_get_var1_long: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_LONG)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_float(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    float value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_FLOAT);
		err = nc_get_var1_float(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_FLOAT)) {
                    if (expect >= float_min && expect <= float_max) {
			IF (err) {
			    error("nc_get_var1_float: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_FLOAT)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}

/* 
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
void
check_vars_double(const char *filename)
{
    int  ncid;                  /* netCDF id */
    size_t index[MAX_RANK];
    int  err;           /* status */
    int  d;
    int  i;
    size_t  j;
    double value;
    nc_type datatype;
    int ndims;
    int dimids[MAX_RANK];
    double expect;
    char name[NC_MAX_NAME];
    size_t length;
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    err = nc_open(filename, NC_NOWRITE, &ncid);
    IF (err)
        error("nc_open: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
	if (canConvert) {
	    err = nc_inq_var(ncid, i, name, &datatype, &ndims, dimids, NULL);
	    IF (err)
		error("nc_inq_var: %s", nc_strerror(err));
	    IF (strcmp(name, var_name[i]) != 0)
		error("Unexpected var_name");
	    IF (datatype != var_type[i])
		error("Unexpected type");
	    IF (ndims != var_rank[i])
		error("Unexpected rank");
	    for (j = 0; j < ndims; j++) {
		err = nc_inq_dim(ncid, dimids[j], 0, &length);
		IF (err)
		    error("nc_inq_dim: %s", nc_strerror(err));
		IF (length != var_shape[i][j])
		    error("Unexpected shape");
	    }
	    for (j = 0; j < var_nels[i]; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err)
		    error("error in toMixedBase 2");
		expect = hash4( var_type[i], var_rank[i], index, NCT_DOUBLE);
		err = nc_get_var1_double(ncid, i, index, &value);
		if (inRange3(expect,datatype,NCT_DOUBLE)) {
                    if (expect >= double_min && expect <= double_max) {
			IF (err) {
			    error("nc_get_var1_double: %s", nc_strerror(err));
			} else {
                            IF (!equal(value,expect,var_type[i],NCT_DOUBLE)) {
				error("Var value read not that expected");
				if (verbose) {
				    error("\n");
				    error("varid: %d, ", i);
				    error("var_name: %s, ", var_name[i]);
				    error("index:");
				    for (d = 0; d < var_rank[i]; d++)
					error(" %d", index[d]);
				    error(", expect: %g, ", expect);
				    error("got: %g", (double) value);
				}
			    } else {
				++nok;
			    }
			}
		    }
		}
	    }
	}
    }
    err = nc_close (ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));
    print_nok(nok);
}




/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_text(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    text value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_TEXT);
		    if (inRange3(expect[k], datatype, NCT_TEXT)) {
			++nInExtRange;
			if (expect[k] >= text_min && expect[k] <= text_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_text(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_TEXT)
                            && expect[k] >= text_min && expect[k] <= text_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_TEXT)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_uchar(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    uchar value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_UCHAR);
		    if (inRange3(expect[k], datatype, NCT_UCHAR)) {
			++nInExtRange;
			if (expect[k] >= uchar_min && expect[k] <= uchar_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_uchar(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_UCHAR)
                            && expect[k] >= uchar_min && expect[k] <= uchar_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_UCHAR)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_schar(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    schar value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_SCHAR);
		    if (inRange3(expect[k], datatype, NCT_SCHAR)) {
			++nInExtRange;
			if (expect[k] >= schar_min && expect[k] <= schar_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_schar(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_SCHAR)
                            && expect[k] >= schar_min && expect[k] <= schar_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_SCHAR)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_short(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    short value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_SHORT);
		    if (inRange3(expect[k], datatype, NCT_SHORT)) {
			++nInExtRange;
			if (expect[k] >= short_min && expect[k] <= short_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_short(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_SHORT)
                            && expect[k] >= short_min && expect[k] <= short_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_SHORT)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_int(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    int value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_INT == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_INT);
		    if (inRange3(expect[k], datatype, NCT_INT)) {
			++nInExtRange;
			if (expect[k] >= int_min && expect[k] <= int_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_int(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_INT)
                            && expect[k] >= int_min && expect[k] <= int_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_INT)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_long(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    long value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_LONG == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_LONG);
		    if (inRange3(expect[k], datatype, NCT_LONG)) {
			++nInExtRange;
			if (expect[k] >= long_min && expect[k] <= long_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_long(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_LONG)
                            && expect[k] >= long_min && expect[k] <= long_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_LONG)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_float(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    float value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_FLOAT);
		    if (inRange3(expect[k], datatype, NCT_FLOAT)) {
			++nInExtRange;
			if (expect[k] >= float_min && expect[k] <= float_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_float(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_FLOAT)
                            && expect[k] >= float_min && expect[k] <= float_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_FLOAT)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}

/* 
 *  check all attributes in file which are (text/numeric) compatible with TYPE
 *  ignore any attributes containing values outside range of TYPE
 */
void
check_atts_double(int  ncid)
{
    int  err;           /* status */
    int  i;
    int  j;
    size_t  k;
    double value[MAX_NELS];
    nc_type datatype;
    double expect[MAX_NELS];
    size_t length;
    size_t nInExtRange;  /* number values within external range */
    size_t nInIntRange;  /* number values within internal range */
    int canConvert;     /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
	    canConvert = (ATT_TYPE(i,j) == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
	    if (canConvert) {
		err = nc_inq_att(ncid, i, ATT_NAME(i,j), &datatype, &length);
		IF (err)
		    error("nc_inq_att: %s", nc_strerror(err));
		IF (datatype != ATT_TYPE(i,j))
		error("nc_inq_att: unexpected type");
		IF (length != ATT_LEN(i,j))
		    error("nc_inq_att: unexpected length");
		assert(length <= MAX_NELS);
		nInIntRange = nInExtRange = 0;
		for (k = 0; k < length; k++) {
		    expect[k] = hash4( datatype, -1, &k, NCT_DOUBLE);
		    if (inRange3(expect[k], datatype, NCT_DOUBLE)) {
			++nInExtRange;
			if (expect[k] >= double_min && expect[k] <= double_max)
			    ++nInIntRange;
		    }
		}
		err = nc_get_att_double(ncid, i, ATT_NAME(i,j), value);
                if (nInExtRange == length && nInIntRange == length) {
		    IF (err)
			error("%s", nc_strerror(err));
                } else {
                    IF (err != 0 && err != NC_ERANGE)
                        error("OK or Range error: status = %d", err);
                }
		for (k = 0; k < length; k++) {
                    if (inRange3(expect[k],datatype,NCT_DOUBLE)
                            && expect[k] >= double_min && expect[k] <= double_max) {
                        IF (!equal(value[k],expect[k],datatype,NCT_DOUBLE)) {
                            error("att. value read not that expected");
                            if (verbose) {
                                error("\n");
                                error("varid: %d, ", i);
                                error("att_name: %s, ", ATT_NAME(i,j));
                                error("element number: %d ", k);
                                error("expect: %g, ", expect[k]);
                                error("got: %g", (double) value[k]);
                            }
                        } else {
                            nok++;
                        }
                    }
                }
            }                                               
        }
    }

    print_nok(nok);
}




void
test_nc_put_var1_text(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    text value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_text(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_text(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_text(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_text( var_type[i], var_rank[i], index, NCT_TEXT);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_text(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_text(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_TEXT)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_text(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_uchar(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    uchar value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_uchar(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_uchar(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_uchar(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_uchar( var_type[i], var_rank[i], index, NCT_UCHAR);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_uchar(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_uchar(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_UCHAR)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_uchar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_schar(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    schar value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_schar(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_schar(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_schar(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_schar( var_type[i], var_rank[i], index, NCT_SCHAR);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_schar(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_schar(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_SCHAR)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_schar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_short(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    short value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_short(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_short(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_short(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_short( var_type[i], var_rank[i], index, NCT_SHORT);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_short(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_short(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_SHORT)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_short(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_int(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_int(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_int(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_int(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_int( var_type[i], var_rank[i], index, NCT_INT);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_int(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_int(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_INT)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_int(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_long(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    long value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_long(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_long(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_long(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_long( var_type[i], var_rank[i], index, NCT_LONG);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_long(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_long(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_LONG)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_long(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_float(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    float value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_float(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_float(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_float(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_float( var_type[i], var_rank[i], index, NCT_FLOAT);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_float(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_float(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_FLOAT)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_float(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var1_double(void)
{
    int ncid;
    int i;
    int j;
    int err;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    double value = 5;	/* any value would do - only for error cases */

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
        for (j = 0; j < var_rank[i]; j++)
            index[j] = 0;
        err = nc_put_var1_double(BAD_ID, i, index, &value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var1_double(ncid, BAD_VARID, index, &value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		index[j] = var_shape[i][j];
		err = nc_put_var1_double(ncid, i, index, &value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad index: status = %d", err);
		index[j] = 0;
	    }
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err) 
		error("error in toMixedBase 1");
            value = hash_double( var_type[i], var_rank[i], index, NCT_DOUBLE);
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_var1_double(ncid, i, NULL, &value);
	    else
		err = nc_put_var1_double(ncid, i, index, &value);
	    if (canConvert) {
		if (inRange3(value, var_type[i],NCT_DOUBLE)) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE) {
			error("Range error: status = %d", err);
			error("\n\t\tfor type %s value %.17e %ld",
				s_nc_type(var_type[i]),
				(double)value, (long)value);
		    }
		}
	    } else {
		IF (err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_double(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}




void
test_nc_put_var_text(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    text value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_text(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_text(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_text(var_type[i], var_rank[i], index, NCT_TEXT);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_TEXT);
	}
        err = nc_put_var_text(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_text(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_text(var_type[i], var_rank[i], index, NCT_TEXT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_TEXT);
	    }
	    err = nc_put_var_text(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_text(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_uchar(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    uchar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_uchar(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_uchar(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_uchar(var_type[i], var_rank[i], index, NCT_UCHAR);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_UCHAR);
	}
        err = nc_put_var_uchar(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_uchar(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_uchar(var_type[i], var_rank[i], index, NCT_UCHAR);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_UCHAR);
	    }
	    err = nc_put_var_uchar(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_uchar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_schar(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    schar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_schar(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_schar(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_schar(var_type[i], var_rank[i], index, NCT_SCHAR);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_SCHAR);
	}
        err = nc_put_var_schar(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_schar(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_schar(var_type[i], var_rank[i], index, NCT_SCHAR);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_SCHAR);
	    }
	    err = nc_put_var_schar(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_schar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_short(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    short value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_short(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_short(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_short(var_type[i], var_rank[i], index, NCT_SHORT);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_SHORT);
	}
        err = nc_put_var_short(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_short(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_short(var_type[i], var_rank[i], index, NCT_SHORT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_SHORT);
	    }
	    err = nc_put_var_short(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_short(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_int(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    int value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_int(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_int(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_int(var_type[i], var_rank[i], index, NCT_INT);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_INT);
	}
        err = nc_put_var_int(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_int(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_int(var_type[i], var_rank[i], index, NCT_INT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_INT);
	    }
	    err = nc_put_var_int(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_int(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_long(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    long value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_long(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_long(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_long(var_type[i], var_rank[i], index, NCT_LONG);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_LONG);
	}
        err = nc_put_var_long(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_long(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_long(var_type[i], var_rank[i], index, NCT_LONG);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_LONG);
	    }
	    err = nc_put_var_long(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_long(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_float(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    float value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_float(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_float(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_float(var_type[i], var_rank[i], index, NCT_FLOAT);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_FLOAT);
	}
        err = nc_put_var_float(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_float(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_float(var_type[i], var_rank[i], index, NCT_FLOAT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_FLOAT);
	    }
	    err = nc_put_var_float(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_float(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_var_double(void)
{
    int ncid;
    int varid;
    int i;
    int j;
    int err;
    int nels;
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    double value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        err = nc_put_var_double(BAD_ID, i, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_var_double(ncid, BAD_VARID, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);

	nels = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    nels *= var_shape[i][j];
	}
	for (allInExtRange = 1, j = 0; j < nels; j++) {
	    err = toMixedBase(j, var_rank[i], var_shape[i], index);
	    IF (err) 
		error("error in toMixedBase 1");
	    value[j]= hash_double(var_type[i], var_rank[i], index, NCT_DOUBLE);
	    allInExtRange = allInExtRange 
		&& inRange3(value[j], var_type[i], NCT_DOUBLE);
	}
        err = nc_put_var_double(ncid, i, value);
	if (canConvert) {
	    if (allInExtRange) {
		IF (err) 
		    error("%s", nc_strerror(err));
	    } else {
		IF (err != NC_ERANGE && var_dimid[i][0] != RECDIM)
		    error("range error: status = %d", err);
	    }
	} else {       /* should flag wrong type even if nothing to write */
	    IF (nels > 0 && err != NC_ECHAR)
		error("wrong type: status = %d", err);
	}
    }

        /* Preceeding has written nothing for record variables, now try */
        /* again with more than 0 records */

	/* Write record number NRECS to force writing of preceding records */
	/* Assumes variable cr is char vector with UNLIMITED dimension */
    err = nc_inq_varid(ncid, "cr", &varid);
    IF (err)
        error("nc_inq_varid: %s", nc_strerror(err));
    index[0] = NRECS-1;
    err = nc_put_var1_text(ncid, varid, index, "x");
    IF (err)
        error("nc_put_var1_text: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
        if (var_dimid[i][0] == RECDIM) {  /* only test record variables here */
	    canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
	    assert(var_rank[i] <= MAX_RANK);
	    assert(var_nels[i] <= MAX_NELS);
	    err = nc_put_var_double(BAD_ID, i, value);

	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		nels *= var_shape[i][j];
	    }
	    for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], var_shape[i], index);
		IF (err) 
		    error("error in toMixedBase 1");
		value[j]= hash_double(var_type[i], var_rank[i], index, NCT_DOUBLE);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_DOUBLE);
	    }
	    err = nc_put_var_double(ncid, i, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
	    }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_double(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}




void
test_nc_put_vara_text(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    text value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_text(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_text(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_text(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_text(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_text(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_text(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_text(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_text(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_text(var_type[i], var_rank[i], index, NCT_TEXT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_TEXT);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_text(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_text(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_text(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_uchar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    uchar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_uchar(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_uchar(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_uchar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_uchar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_uchar(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_uchar(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_uchar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_uchar(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_uchar(var_type[i], var_rank[i], index, NCT_UCHAR);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_UCHAR);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_uchar(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_uchar(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_uchar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_schar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    schar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_schar(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_schar(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_schar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_schar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_schar(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_schar(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_schar(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_schar(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_schar(var_type[i], var_rank[i], index, NCT_SCHAR);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_SCHAR);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_schar(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_schar(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_schar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_short(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    short value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_short(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_short(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_short(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_short(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_short(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_short(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_short(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_short(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_short(var_type[i], var_rank[i], index, NCT_SHORT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_SHORT);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_short(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_short(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_short(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_int(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    int value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_int(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_int(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_int(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_int(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_int(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_int(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_int(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_int(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_int(var_type[i], var_rank[i], index, NCT_INT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_INT);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_int(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_int(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_int(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_long(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    long value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_long(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_long(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_long(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_long(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_long(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_long(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_long(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_long(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_long(var_type[i], var_rank[i], index, NCT_LONG);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_LONG);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_long(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_long(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_long(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_float(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    float value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_float(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_float(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_float(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_float(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_float(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_float(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_float(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_float(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_float(var_type[i], var_rank[i], index, NCT_FLOAT);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_FLOAT);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_float(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_float(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_float(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_vara_double(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int err;
    int nslabs;
    int nels;
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t index[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    double value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
        error("nc_enddef: %s", nc_strerror(err));

    value[0] = 0;
    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);
        for (j = 0; j < var_rank[i]; j++) {
            start[j] = 0;
            edge[j] = 1;
	}
        err = nc_put_vara_double(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_double(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_double(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vara_double(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
	    }
        }
            /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 0;
	}
        err = nc_put_vara_double(BAD_ID, i, start, edge, value);
        IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
        err = nc_put_vara_double(ncid, BAD_VARID, start, edge, value);
        IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
        for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vara_double(ncid, i, start, edge, value);
		IF (canConvert && err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
	    }
        }
	err = nc_put_vara_double(ncid, i, start, edge, value);
	if (canConvert) {
	    IF (err) 
		error("%s", nc_strerror(err));
	} else {
	    IF (err != NC_ECHAR)
		error("wrong type: status = %d", err);
        }
        for (j = 0; j < var_rank[i]; j++) {
            edge[j] = 1;
	}

	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
            mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	for (k = 0; k < nslabs; k++) {
	    nels = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		nels *= edge[j];
	    }
            for (allInExtRange = 1, j = 0; j < nels; j++) {
		err = toMixedBase(j, var_rank[i], edge, index);
		IF (err) 
		    error("error in toMixedBase 1");
		for (d = 0; d < var_rank[i]; d++) 
		    index[d] += start[d];
		value[j]= hash_double(var_type[i], var_rank[i], index, NCT_DOUBLE);
		allInExtRange = allInExtRange 
		    && inRange3(value[j], var_type[i], NCT_DOUBLE);
	    }
	    if (var_rank[i] == 0 && i%2 == 0)
		err = nc_put_vara_double(ncid, i, NULL, NULL, value);
	    else
		err = nc_put_vara_double(ncid, i, start, edge, value);
	    if (canConvert) {
		if (allInExtRange) {
		    IF (err) 
			error("%s", nc_strerror(err));
		} else {
		    IF (err != NC_ERANGE)
			error("range error: status = %d", err);
		}
	    } else {
		IF (nels > 0 && err != NC_ECHAR)
		    error("wrong type: status = %d", err);
            }
        }
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_double(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}




void
test_nc_put_vars_text(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    text value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_text(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_text(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_text(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_text(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_text(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_text(var_type[i], var_rank[i], index2, 
			NCT_TEXT);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_TEXT);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_text(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_text(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_text(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_uchar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    uchar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_uchar(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_uchar(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_uchar(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_uchar(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_uchar(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_uchar(var_type[i], var_rank[i], index2, 
			NCT_UCHAR);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_UCHAR);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_uchar(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_uchar(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_uchar(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_schar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    schar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_schar(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_schar(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_schar(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_schar(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_schar(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_schar(var_type[i], var_rank[i], index2, 
			NCT_SCHAR);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_SCHAR);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_schar(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_schar(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_schar(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_short(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    short value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_short(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_short(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_short(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_short(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_short(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_short(var_type[i], var_rank[i], index2, 
			NCT_SHORT);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_SHORT);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_short(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_short(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_short(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_int(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    int value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_int(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_int(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_int(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_int(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_int(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_int(var_type[i], var_rank[i], index2, 
			NCT_INT);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_INT);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_int(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_int(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_int(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_long(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    long value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_long(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_long(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_long(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_long(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_long(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_long(var_type[i], var_rank[i], index2, 
			NCT_LONG);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_LONG);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_long(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_long(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_long(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_float(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    float value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_float(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_float(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_float(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_float(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_float(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_float(var_type[i], var_rank[i], index2, 
			NCT_FLOAT);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_FLOAT);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_float(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_float(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_float(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}

void
test_nc_put_vars_double(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    double value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	}
	err = nc_put_vars_double(BAD_ID, i, start, edge, stride, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_vars_double(ncid, BAD_VARID, start, edge, stride, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_vars_double(ncid, i, start, edge, stride, value);
	      if(!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF(err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_vars_double(ncid, i, start, edge, stride, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_vars_double(ncid, i, start, edge, stride, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
              }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
	    for (m = 0; m < nstarts; m++) {
		err = toMixedBase(m, var_rank[i], sstride, index);
		IF (err)
		    error("error in toMixedBase");
		nels = 1;
		for (j = 0; j < var_rank[i]; j++) {
		    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
		    nels *= count[j];
		    index[j] += start[j];
		}
		    /* Random choice of forward or backward */
/* TODO
		if ( roll(2) ) {
		    for (j = 0; j < var_rank[i]; j++) {
			index[j] += (count[j] - 1) * stride[j];
			stride[j] = -stride[j];
		    }
		}
*/
		for (allInExtRange = 1, j = 0; j < nels; j++) {
		    err = toMixedBase(j, var_rank[i], count, index2);
		    IF (err)
			error("error in toMixedBase");
		    for (d = 0; d < var_rank[i]; d++)
			index2[d] = index[d] + index2[d] * stride[d];
		    value[j] = hash_double(var_type[i], var_rank[i], index2, 
			NCT_DOUBLE);
		    allInExtRange = allInExtRange 
			&& inRange3(value[j], var_type[i], NCT_DOUBLE);
		}
		if (var_rank[i] == 0 && i%2 == 0)
		    err = nc_put_vars_double(ncid, i, NULL, NULL, stride, value);
		else
		    err = nc_put_vars_double(ncid, i, index, count, stride, value);
		if (canConvert) {
		    if (allInExtRange) {
			IF (err) 
			    error("%s", nc_strerror(err));
		    } else {
			IF (err != NC_ERANGE)
			    error("range error: status = %d", err);
		    }
		} else {
		    IF (nels > 0 && err != NC_ECHAR)
			error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_double(scratch);

    err = remove(scratch);
    IF (err)
	error("remove of %s failed", scratch);
}




void
test_nc_put_varm_text(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    text value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_TEXT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_text(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_text(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_text(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_text(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_text(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_text(var_type[i], var_rank[i], index2,
                        NCT_TEXT);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_TEXT);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_text(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_text(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_text(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_uchar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    uchar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_UCHAR == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_uchar(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_uchar(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_uchar(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_uchar(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_uchar(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_uchar(var_type[i], var_rank[i], index2,
                        NCT_UCHAR);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_UCHAR);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_uchar(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_uchar(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_uchar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_schar(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    schar value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SCHAR == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_schar(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_schar(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_schar(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_schar(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_schar(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_schar(var_type[i], var_rank[i], index2,
                        NCT_SCHAR);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_SCHAR);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_schar(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_schar(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_schar(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_short(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    short value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_SHORT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_short(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_short(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_short(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_short(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_short(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_short(var_type[i], var_rank[i], index2,
                        NCT_SHORT);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_SHORT);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_short(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_short(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_short(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_int(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    int value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_INT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_int(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_int(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_int(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_int(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_int(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_int(var_type[i], var_rank[i], index2,
                        NCT_INT);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_INT);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_int(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_int(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_int(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_long(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    long value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_LONG == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_long(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_long(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_long(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_long(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_long(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_long(var_type[i], var_rank[i], index2,
                        NCT_LONG);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_LONG);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_long(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_long(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_long(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_float(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    float value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_FLOAT == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_float(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_float(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_float(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_float(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_float(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_float(var_type[i], var_rank[i], index2,
                        NCT_FLOAT);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_FLOAT);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_float(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_float(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_float(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_varm_double(void)
{
    int ncid;
    int d;
    int i;
    int j;
    int k;
    int m;
    int err;
    int nels;
    int nslabs;
    int nstarts;        /* number of different starts */
    size_t start[MAX_RANK];
    size_t edge[MAX_RANK];
    size_t index[MAX_RANK];
    size_t index2[MAX_RANK];
    size_t mid[MAX_RANK];
    size_t count[MAX_RANK];
    size_t sstride[MAX_RANK];
    ptrdiff_t stride[MAX_RANK];
    ptrdiff_t imap[MAX_RANK];
    int canConvert;	/* Both text or both numeric */
    int allInExtRange;	/* all values within external range? */
    double value[MAX_NELS];

    err = nc_create(scratch, NC_CLOBBER, &ncid);
    IF (err) {
	error("nc_create: %s", nc_strerror(err));
	return;
    }
    def_dims(ncid);
    def_vars(ncid);
    err = nc_enddef(ncid);
    IF (err)
	error("nc_enddef: %s", nc_strerror(err));

    for (i = 0; i < NVARS; i++) {
	canConvert = (var_type[i] == NC_CHAR) == (NCT_DOUBLE == NCT_TEXT);
	assert(var_rank[i] <= MAX_RANK);
	assert(var_nels[i] <= MAX_NELS);
	for (j = 0; j < var_rank[i]; j++) {
	    start[j] = 0;
	    edge[j] = 1;
	    stride[j] = 1;
	    imap[j] = 1;
	}
	err = nc_put_varm_double(BAD_ID, i, start, edge, stride, imap, value);
	IF (err != NC_EBADID) 
	    error("bad ncid: status = %d", err);
	err = nc_put_varm_double(ncid, BAD_VARID, start, edge, stride, imap, value);
	IF (err != NC_ENOTVAR) 
	    error("bad var id: status = %d", err);
	for (j = 0; j < var_rank[i]; j++) {
	    if (var_dimid[i][j] > 0) {		/* skip record dim */
		start[j] = var_shape[i][j];
		err = nc_put_varm_double(ncid, i, start, edge, stride, imap, value);
	      if (!canConvert) {
		IF(err != NC_ECHAR)
			error("conversion: status = %d", err);
	      } else {
		IF (err != NC_EINVALCOORDS)
		    error("bad start: status = %d", err);
		start[j] = 0;
		edge[j] = var_shape[i][j] + 1;
		err = nc_put_varm_double(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_EEDGE)
		    error("bad edge: status = %d", err);
		edge[j] = 1;
		stride[j] = 0;
		err = nc_put_varm_double(ncid, i, start, edge, stride, imap, value);
		IF (err != NC_ESTRIDE)
		    error("bad stride: status = %d", err);
		stride[j] = 1;
	      }
	    }
	}
	    /* Choose a random point dividing each dim into 2 parts */
	    /* Put 2^rank (nslabs) slabs so defined */
	nslabs = 1;
	for (j = 0; j < var_rank[i]; j++) {
	    mid[j] = roll( var_shape[i][j] );
	    nslabs *= 2;
	}
	    /* bits of k determine whether to put lower or upper part of dim */
	    /* choose random stride from 1 to edge */
	for (k = 0; k < nslabs; k++) {
	    nstarts = 1;
	    for (j = 0; j < var_rank[i]; j++) {
		if ((k >> j) & 1) {
		    start[j] = 0;
		    edge[j] = mid[j];
		}else{
		    start[j] = mid[j];
		    edge[j] = var_shape[i][j] - mid[j];
		}
		sstride[j] = stride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
		nstarts *= stride[j];
	    }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err)
                    error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i]; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                    /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i]; j++) {
                        index[j] += (count[j] - 1) * stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    j = var_rank[i] - 1;
                    imap[j] = 1;
                    for (; j > 0; j--)
                        imap[j-1] = imap[j] * count[j];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err)
                        error("error in toMixedBase");
                    for (d = 0; d < var_rank[i]; d++)
                        index2[d] = index[d] + index2[d] * stride[d];
                    value[j] = hash_double(var_type[i], var_rank[i], index2,
                        NCT_DOUBLE);
                    allInExtRange = allInExtRange
                        && inRange3(value[j], var_type[i], NCT_DOUBLE);
                }
                if (var_rank[i] == 0 && i%2 == 0)
                    err = nc_put_varm_double(ncid,i,NULL,NULL,NULL,NULL,value);
                else
                    err = nc_put_varm_double(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err)
                            error("%s", nc_strerror(err));
                    } else {
                        IF (err != NC_ERANGE)
                            error("range error: status = %d", err);
                    }
                } else {
                    IF (nels > 0 && err != NC_ECHAR)
                        error("wrong type: status = %d", err);
		}
	    }
	}
    }

    err = nc_close(ncid);
    IF (err) 
	error("nc_close: %s", nc_strerror(err));

    check_vars_double(scratch);

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}



void
test_nc_put_att_text(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    text value[MAX_NELS];

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (ATT_TYPE(i,j) == NC_CHAR) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_text(BAD_ID, i, ATT_NAME(i,j), ATT_LEN(i,j), 
		    value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_text(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		for (k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash(ATT_TYPE(i,j), -1, &k);
		}
		err = nc_put_att_text(ncid, i, ATT_NAME(i,j), 
		    ATT_LEN(i,j), value);
		IF (err) {
		    error("%s", nc_strerror(err));
		}
	    }
        }
    }

    check_atts_text(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}



void
test_nc_put_att_uchar(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    uchar value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_uchar(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_uchar(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_uchar(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_uchar(ATT_TYPE(i,j), -1, &k, NCT_UCHAR);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_UCHAR);
		}
		err = nc_put_att_uchar(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_uchar(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_schar(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    schar value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_schar(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_schar(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_schar(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_schar(ATT_TYPE(i,j), -1, &k, NCT_SCHAR);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_SCHAR);
		}
		err = nc_put_att_schar(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_schar(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_short(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    short value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_short(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_short(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_short(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_short(ATT_TYPE(i,j), -1, &k, NCT_SHORT);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_SHORT);
		}
		err = nc_put_att_short(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_short(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_int(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    int value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_int(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_int(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_int(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_int(ATT_TYPE(i,j), -1, &k, NCT_INT);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_INT);
		}
		err = nc_put_att_int(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_int(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_long(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    long value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_long(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_long(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_long(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_long(ATT_TYPE(i,j), -1, &k, NCT_LONG);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_LONG);
		}
		err = nc_put_att_long(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_long(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_float(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    float value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_float(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_float(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_float(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_float(ATT_TYPE(i,j), -1, &k, NCT_FLOAT);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_FLOAT);
		}
		err = nc_put_att_float(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_float(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}

void
test_nc_put_att_double(void)
{
    int ncid;
    int i;
    int j;
    size_t k;
    int err;
    double value[MAX_NELS];
    int allInExtRange;  /* all values within external range? */

    err = nc_create(scratch, NC_NOCLOBBER, &ncid);
    IF (err) {
        error("nc_create: %s", nc_strerror(err));
        return;
    }
    def_dims(ncid);
    def_vars(ncid);

    for (i = -1; i < NVARS; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
		assert(ATT_LEN(i,j) <= MAX_NELS);
		err = nc_put_att_double(BAD_ID, i, ATT_NAME(i,j), ATT_TYPE(i,j), 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADID)
		    error("bad ncid: status = %d", err);
		err = nc_put_att_double(ncid, BAD_VARID, ATT_NAME(i,j), 
		    ATT_TYPE(i,j), ATT_LEN(i,j), value);
		IF (err != NC_ENOTVAR)
		    error("bad var id: status = %d", err);
		err = nc_put_att_double(ncid, i, ATT_NAME(i,j), BAD_TYPE, 
		    ATT_LEN(i,j), value);
		IF (err != NC_EBADTYPE)
		    error("bad type: status = %d", err);
		for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
		    value[k] = hash_double(ATT_TYPE(i,j), -1, &k, NCT_DOUBLE);
		    allInExtRange = allInExtRange
			&& inRange3(value[k], ATT_TYPE(i,j), NCT_DOUBLE);
		}
		err = nc_put_att_double(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j),
		    ATT_LEN(i,j), value);
		if (allInExtRange) {
		    IF (err)
			error("%s", nc_strerror(err));
		} else {
                    IF (err != NC_ERANGE)
                        error("range error: status = %d", err);
		}
	    }
        }
    }

    check_atts_double(ncid);
    err = nc_close(ncid);
    IF (err)
        error("nc_close: %s", nc_strerror(err));

    err = remove(scratch);
    IF (err)
        error("remove of %s failed", scratch);
}


