/* This is part of the netCDF package. Copyright 2020 University
   Corporation for Atmospheric Research/Unidata. See COPYRIGHT file
   for conditions of use.

   More tests for HDF5 datasets. These are not intended to be
   exhaustive tests, but they use HDF5 the same way that netCDF-4
   does, so if these tests don't work, than netCDF-4 won't work
   either.

   Ed Hartnett
*/

#include "h5_err_macros.h"
#include <hdf5.h>
#include <H5DSpublic.h>

#define FILE_NAME "tst_h_vars2.h5"
#define STR_LEN 255

int
main()
{
    printf("\n*** Checking HDF5 variable functions some more.\n");
    /* If HDF5 has working ordering of variables, then the following
     * test will work.*/
    printf("*** Checking HDF5 variable ordering...");

#define NUM_ELEMENTS 6
#define MAX_SYMBOL_LEN 2
#define ELEMENTS_NAME "Elements"
    {
        hid_t did[NUM_ELEMENTS], fapl_id, fcpl_id, gcpl_id;
        hsize_t num_obj;
        hid_t fileid, grpid, spaceid;
        int i;
#if H5_VERSION_GE(1,12,0)
        H5O_info2_t obj_info;
#else
        H5O_info_t obj_info;
#endif
        char names[NUM_ELEMENTS][MAX_SYMBOL_LEN + 1] = {"H", "He", "Li", "Be", "B", "C"};
        char name[MAX_SYMBOL_LEN + 1];
        ssize_t size;

        /* Create file, setting latest_format in access propertly list
         * and H5P_CRT_ORDER_TRACKED in the creation property list. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
        if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
        if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

        /* Create group, with link_creation_order set in the group
         * creation property list. */
        if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) ERR;
        if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
        if ((grpid = H5Gcreate_anon(fileid, gcpl_id, H5P_DEFAULT)) < 0) ERR;
        if ((H5Olink(grpid, fileid, ELEMENTS_NAME, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;

        /* Create a scalar space. */
        if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;

        /* Create the variables, one per element. */
        for (i = 0; i < NUM_ELEMENTS; i++)
        {
            if ((did[i] = H5Dcreate1(grpid, names[i], H5T_NATIVE_INT,
                                    spaceid, H5P_DEFAULT)) < 0) ERR;
            if (H5Dclose(did[i]) < 0) ERR;
        }

        if (H5Pclose(fapl_id) < 0 ||
            H5Pclose(gcpl_id) < 0 ||
            H5Sclose(spaceid) < 0 ||
            H5Gclose(grpid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

        /* Now reopen the file and check the order. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
        if ((grpid = H5Gopen1(fileid, ELEMENTS_NAME)) < 0) ERR;

        if (H5Gget_num_objs(grpid, &num_obj) < 0) ERR;
        if (num_obj != NUM_ELEMENTS) ERR;
        for (i = 0; i < num_obj; i++)
        {
#if H5_VERSION_GE(1,12,0)
            if (H5Oget_info_by_idx3(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                                    i, &obj_info, H5O_INFO_BASIC, H5P_DEFAULT) < 0) ERR;
#else
            if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                                   i, &obj_info, H5P_DEFAULT) < 0) ERR;
#endif
            if (obj_info.type != H5O_TYPE_DATASET) ERR;
            if ((size = H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i,
                                           NULL, 0, H5P_DEFAULT)) < 0) ERR;
            H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i,
                               name, size+1, H5P_DEFAULT);
            if (strcmp(name, names[i])) ERR;
        }
        if (H5Pclose(fapl_id) < 0 ||
            H5Gclose(grpid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

    }
    SUMMARIZE_ERR;
    printf("*** Checking HDF5 variable ordering in root group...");

#define NUM_DIMSCALES 2
#define MAX_SYMBOL_LEN 2
#define DIM1_LEN 3
#define DIMSCALE_NAME "Joe"
#define NAME_ATTRIBUTE "short"
    {
        hid_t fapl_id, fcpl_id;
        hid_t fileid, grpid;
        hsize_t num_obj;
        int i;
#if H5_VERSION_GE(1,12,0)
        H5O_info2_t obj_info;
#else
        H5O_info_t obj_info;
#endif
        char names[NUM_DIMSCALES][MAX_SYMBOL_LEN + 1] = {"b", "a"};
        char name[MAX_SYMBOL_LEN + 1];
        hid_t dimscaleid;
        hid_t dimscale_spaceid;
        hsize_t dimscale_dims[1] = {DIM1_LEN};
        ssize_t size;

        /* Create file, setting latest_format in access propertly list
         * and H5P_CRT_ORDER_TRACKED in the creation property list. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
        if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
        if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

        if ((dimscale_spaceid = H5Screate_simple(1, dimscale_dims,
                                                 dimscale_dims)) < 0) ERR;
        /* Create the variables, one per element. */
        for (i = 0; i < NUM_DIMSCALES; i++)
        {
            /* Create our dimension scale. Use the built-in NAME attribute
             * on the dimscale. */
            if ((dimscaleid = H5Dcreate1(fileid, names[i], H5T_NATIVE_INT,
                                        dimscale_spaceid, H5P_DEFAULT)) < 0) ERR;
            if (H5DSset_scale(dimscaleid, NAME_ATTRIBUTE) < 0) ERR;

            if (H5Dclose(dimscaleid) < 0) ERR;
        }

        if (H5Pclose(fapl_id) < 0 ||
            H5Pclose(fcpl_id) < 0 ||
            H5Sclose(dimscale_spaceid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

        /* Now reopen the file and check the order. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
        if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

        if (H5Gget_num_objs(grpid, &num_obj) < 0) ERR;
        if (num_obj != NUM_DIMSCALES) ERR;
        for (i = 0; i < num_obj; i++)
        {
#if H5_VERSION_GE(1,12,0)
            if (H5Oget_info_by_idx3(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                                    i, &obj_info, H5O_INFO_BASIC, H5P_DEFAULT) < 0) ERR;
#else
            if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                                   i, &obj_info, H5P_DEFAULT) < 0) ERR;
#endif
            if (obj_info.type != H5O_TYPE_DATASET) ERR;
            if ((size = H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i,
                                           NULL, 0, H5P_DEFAULT)) < 0) ERR;
            if (H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, i,
                                   name, size+1, H5P_DEFAULT) < 0) ERR;
            if (strcmp(name, names[i])) ERR;
        }
        if (H5Pclose(fapl_id) < 0 ||
            H5Gclose(grpid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

    }
    SUMMARIZE_ERR;
    printf("*** Checking HDF5 variable ordering flags with redef-type situations...");

#define NUM_ELEMENTS 6
#define MAX_NAME_LEN 50
#define ELEMENTS_NAME "Elements"
#define VAR_NAME "Sears_Zemansky_and_Young"
    {
        hid_t did, fapl_id, fcpl_id, gcpl_id, attid;
        hsize_t num_obj;
        hid_t fileid, grpid, spaceid;
        float val = 3.1495;
#if H5_VERSION_GE(1,12,0)
        H5O_info2_t obj_info;
#else
        H5O_info_t obj_info;
#endif
        char name[MAX_NAME_LEN + 1];
        ssize_t size;

        /* Create file, setting latest_format in access propertly list
         * and H5P_CRT_ORDER_TRACKED in the creation property list. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
        if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
        if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

        /* Create group, with link_creation_order set in the group
         * creation property list. */
        if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) ERR;
        if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
        if ((grpid = H5Gcreate_anon(fileid, gcpl_id, H5P_DEFAULT)) < 0) ERR;
        if ((H5Olink(grpid, fileid, ELEMENTS_NAME, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;

        /* Create a scalar space. */
        if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;

        /* Create a scalar variable. */
        if ((did = H5Dcreate1(grpid, VAR_NAME, H5T_NATIVE_INT,
                             spaceid, H5P_DEFAULT)) < 0) ERR;
        if (H5Dclose(did) < 0) ERR;

        /* Flush the HDF5 buffers. */
        H5Fflush(fileid, H5F_SCOPE_GLOBAL);

        /* Delete the variable. Just to be mean. */
        if (H5Gunlink(grpid, VAR_NAME) < 0) ERR;

        /* Re-reate the scalar variable. */
        if ((did = H5Dcreate1(grpid, VAR_NAME, H5T_NATIVE_INT,
                             spaceid, H5P_DEFAULT)) < 0) ERR;

        /* Add an attribute. */
        if ((attid = H5Acreate1(did, "Some_Attribute", H5T_NATIVE_FLOAT, spaceid,
                               H5P_DEFAULT)) < 0) ERR;
        if (H5Awrite(attid, H5T_NATIVE_FLOAT, &val) < 0) ERR;

        if (H5Aclose(attid) < 0) ERR;
        if (H5Dclose(did) < 0) ERR;

        if (H5Pclose(fapl_id) < 0 ||
            H5Pclose(gcpl_id) < 0 ||
            H5Sclose(spaceid) < 0 ||
            H5Gclose(grpid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

        /* Now reopen the file and check the order. */
        if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
        if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
        if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
        if ((grpid = H5Gopen1(fileid, ELEMENTS_NAME)) < 0) ERR;

        if (H5Gget_num_objs(grpid, &num_obj) < 0) ERR;
        if (num_obj != 1) ERR;

#if H5_VERSION_GE(1,12,0)
        if (H5Oget_info_by_idx3(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                                0, &obj_info, H5O_INFO_BASIC, H5P_DEFAULT) < 0) ERR;
#else
        if (H5Oget_info_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,
                               0, &obj_info, H5P_DEFAULT) < 0) ERR;
#endif
        if (obj_info.type != H5O_TYPE_DATASET) ERR;
        if ((size = H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0,
                                       NULL, 0, H5P_DEFAULT)) < 0) ERR;
        H5Lget_name_by_idx(grpid, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0,
                           name, size+1, H5P_DEFAULT);
        if (strcmp(name, VAR_NAME)) ERR;
        if (H5Pclose(fapl_id) < 0 ||
            H5Gclose(grpid) < 0 ||
            H5Fclose(fileid) < 0)
            ERR;

    }
    SUMMARIZE_ERR;
    printf("*** Checking HDF5 variable compession and filters...");
    {
#define NUM_ELEMENTS 6
#define MAX_NAME_LEN 50
#define ELEMENTS_NAME "Elements"
#define VAR_NAME "Sears_Zemansky_and_Young"
#define NDIMS 2
#define NX 60
#define NY 120
#define DEFLATE_LEVEL 3
#define SIMPLE_VAR_NAME "data"

	hid_t fapl_id, fcpl_id;
	hid_t datasetid;
	hid_t fileid, grpid, spaceid, plistid;
	int data_in[NX][NY], data_out[NX][NY];
	hsize_t fdims[NDIMS], fmaxdims[NDIMS];
	hsize_t chunksize[NDIMS], dimsize[NDIMS], maxdimsize[NDIMS];
	int x, y;

	/* Create some data to write. */
	for (x = 0; x < NX; x++)
	    for (y = 0; y < NY; y++)
		data_out[x][y] = x * NY + y;

	/* Create file, setting latest_format in access propertly list
	 * and H5P_CRT_ORDER_TRACKED in the creation property list. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
	if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
	if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	dimsize[0] = maxdimsize[0] = NX;
	dimsize[1] = maxdimsize[1] = NY;
	if ((spaceid = H5Screate_simple(NDIMS, dimsize, maxdimsize)) < 0) ERR;

	/* Create property lust. */
	if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;

	/* Set up chunksizes. */
	chunksize[0] = NX;
	chunksize[1] = NY;
	if (H5Pset_chunk(plistid, NDIMS, chunksize) < 0)ERR;

	/* Set up compression. */
	if (H5Pset_deflate(plistid, DEFLATE_LEVEL) < 0) ERR;

	/* Create the variable. */
	if ((datasetid = H5Dcreate1(grpid, SIMPLE_VAR_NAME, H5T_NATIVE_INT,
				   spaceid, plistid)) < 0) ERR;

	/* Write the data. */
	if (H5Dwrite(datasetid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
		     H5P_DEFAULT, data_out) < 0) ERR;

	if (H5Dclose(datasetid) < 0) ERR;
	if (H5Pclose(fapl_id) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;

	/* Now reopen the file and check the order. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if ((datasetid = H5Dopen1(grpid, SIMPLE_VAR_NAME)) < 0) ERR;
	if ((spaceid = H5Dget_space(datasetid)) < 0)
	    if (H5Sget_simple_extent_dims(spaceid, fdims, fmaxdims) > 0) ERR;
	if (H5Dread(datasetid, H5T_NATIVE_INT, H5S_ALL,
		    spaceid, H5P_DEFAULT, data_in) < 0) ERR;

	/* Check the data. */
	for (x = 0; x < NX; x++)
	    for (y = 0; y < NY; y++)
		if (data_in[x][y] != data_out[x][y]) ERR_RET;

	if (H5Pclose(fapl_id) < 0 ||
	    H5Dclose(datasetid) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;
    }
    SUMMARIZE_ERR;
    printf("*** Checking fill value of compound type...");

    {
#define VAR_NAME2 "obs"
#define REF_FILE "ref_tst_compounds.nc"
#define ATT_NAME "_FillValue"

	typedef struct obs_t {
	    char day ;
	    short elev;
	    int count;
	    float relhum;
	    double time;
	} obs_t ;

	obs_t f1, f2;
	obs_t m = {-99, -99, -99, -99, -99};
	hid_t fileid, grpid, attid, typeid, datasetid, native_typeid, propid;
	H5D_fill_value_t fill_status;
	char file_in[STR_LEN * 2];
	size_t type_size;

	if (getenv("srcdir"))
	{
	    strcpy(file_in, getenv("srcdir"));
	    strcat(file_in, "/");
	    strcat(file_in, REF_FILE);
	}
	else
	    strcpy(file_in, REF_FILE);

	/* Open file and read fill value of the variable. */
	if ((fileid = H5Fopen(file_in, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) ERR;
	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;
	if ((datasetid = H5Dopen1(grpid, VAR_NAME2)) < 0) ERR;
	if ((propid = H5Dget_create_plist(datasetid)) < 0) ERR;
	if (H5Pfill_value_defined(propid, &fill_status) < 0) ERR;
	if (fill_status != H5D_FILL_VALUE_USER_DEFINED) ERR;
	if ((typeid = H5Dget_type(datasetid)) < 0) ERR;
	if ((native_typeid = H5Tget_native_type(typeid, H5T_DIR_DEFAULT)) < 0) ERR;
	if (!(type_size = H5Tget_size(native_typeid))) ERR;
	if (type_size != sizeof(obs_t)) ERR;
	if (H5Pget_fill_value(propid, native_typeid, &f1) < 0) ERR;
	if (f1.day != m.day || f1.elev != m.elev || f1.count != m.count ||
	    f1.relhum != m.relhum || f1.time != m.time) ERR;

	/* It's also in an attribute, netCDF style. */
	if ((attid = H5Aopen_name(datasetid, ATT_NAME)) < 0) ERR;
	if ((typeid = H5Aget_type(attid)) < 0) ERR;
	if ((native_typeid = H5Tget_native_type(typeid, H5T_DIR_DEFAULT)) < 0) ERR;
	if (H5Aread(attid, native_typeid, &f2) < 0) ERR;
	if (f2.day != m.day || f2.elev != m.elev || f2.count != m.count ||
	    f2.relhum != m.relhum || f2.time != m.time) ERR;

	if (H5Dclose(datasetid) < 0 ||
	    H5Aclose(attid) < 0 ||
	    H5Tclose(native_typeid) < 0 ||
	    H5Tclose(typeid) < 0 ||
	    H5Pclose(propid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0) ERR;

    }
    SUMMARIZE_ERR;
    printf("*** Checking HDF5 lots of datasets...");
    {
#define NDIMS1 1
#define NUM_DATASETS 10000
#define CHUNKSIZE 1

	hid_t fapl_id, fcpl_id;
	hid_t datasetid[NUM_DATASETS];
	hid_t fileid, grpid, spaceid, plistid;
	hsize_t chunksize[NDIMS1], dimsize[NDIMS1], maxdimsize[NDIMS1];
	char var_name[STR_LEN + 1];
	int v;

	/* Create file, setting latest_format in access propertly list
	 * and H5P_CRT_ORDER_TRACKED in the creation property list. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
	if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
	if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

	/* Open root group. */
	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	/* Create 1 D data space with unlimited dimension. */
	dimsize[0] = 0;
	maxdimsize[0] = H5S_UNLIMITED;
	if ((spaceid = H5Screate_simple(NDIMS1, dimsize, maxdimsize)) < 0) ERR;

	/* Create property list. */
	if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;

	/* Set up chunksizes. */
	chunksize[0] = CHUNKSIZE;
	if (H5Pset_chunk(plistid, NDIMS1, chunksize) < 0)ERR;

	/* Create the variables. */
	for (v = 0; v < NUM_DATASETS; v++)
	{
	    sprintf(var_name, "var_%d", v);
	    /*       printf("creating var %s\n", var_name);*/
	    if ((datasetid[v] = H5Dcreate1(grpid, var_name, H5T_NATIVE_INT,
					  spaceid, plistid)) < 0) ERR_RET;
	}

	/* Close the datasets. */
	for (v = 0; v < NUM_DATASETS; v++)
	    if (H5Dclose(datasetid[v]) < 0) ERR_RET;

	/* Close everything. */
	if (H5Pclose(fapl_id) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;

	/* Now reopen the file and check. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if (H5Pclose(fapl_id) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;
    }
    SUMMARIZE_ERR;
    printf("*** Checking that HDF5 does not allow scalar variable compession...");
#define MAX_NAME_LEN 50
#define DEFLATE_LEVEL 3
#define SIMPLE_VAR_NAME1 "punches"
    {
	hid_t fapl_id, fcpl_id;
	hid_t datasetid;
	hid_t fileid, grpid, spaceid, plistid;
	hsize_t chunksize = 1;

	/* Create file, setting latest_format in access propertly list
	 * and H5P_CRT_ORDER_TRACKED in the creation property list. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
	if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
	if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;

	/* Create property list. */
	if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;

	/* Set chunking. */
	if (H5Pset_chunk(plistid, 1, &chunksize) < 0)ERR;

	/* Set up compression. */
	if (H5Pset_deflate(plistid, DEFLATE_LEVEL) < 0) ERR;

	/* Turn off error messages. The next call will generate a
	 * bunch of error messages on the console. */
	H5Eset_auto2(H5E_DEFAULT, NULL, NULL);

	/* Create the variable. This will not work, because only
	 * chunked datasets can use filters, and scalars can't be
	 * chunked. The H5Dcreate1() call will fail. */
	if ((datasetid = H5Dcreate1(grpid, SIMPLE_VAR_NAME1, H5T_NATIVE_INT,
				   spaceid, plistid)) > 0) ERR;

	/* Turn on error messages back on. */
	H5Eset_auto2(H5E_DEFAULT, (H5E_auto2_t)&H5Eprint1, stderr);

	if (H5Pclose(fapl_id) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;

    }
    SUMMARIZE_ERR;
    printf("*** Checking HDF5 scalar compact dataset...");
    {
	hid_t fapl_id, fcpl_id;
	hid_t datasetid;
	hid_t fileid, grpid, spaceid, plistid;
	hid_t propid;
	int data_in, data_out = 42;
	H5D_layout_t layout;

	/* Create file, setting latest_format in access propertly list
	 * and H5P_CRT_ORDER_TRACKED in the creation property list. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
	if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
	if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;

	/* Create property lust. */
	if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;

	if (H5Pset_layout(plistid, H5D_COMPACT) < 0)ERR;

	/* Create the variable. */
	if ((datasetid = H5Dcreate1(grpid, SIMPLE_VAR_NAME1, H5T_NATIVE_INT,
				   spaceid, plistid)) < 0) ERR;

	/* Write the data. */
	if (H5Dwrite(datasetid, H5T_NATIVE_INT, spaceid, spaceid,
		     H5P_DEFAULT, &data_out) < 0) ERR;

	if ((layout = H5Pget_layout(plistid)) < 0) ERR;
	if (layout != H5D_COMPACT) ERR;

	if (H5Pclose(fapl_id) < 0 ||
	    H5Dclose(datasetid) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;

	/* Now reopen the file and check. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDONLY, fapl_id)) < 0) ERR;
	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if ((datasetid = H5Dopen1(grpid, SIMPLE_VAR_NAME1)) < 0) ERR;
	if ((spaceid = H5Dget_space(datasetid)) < 0) ERR;
	if ((propid = H5Dget_create_plist(datasetid)) < 0) ERR;
	if ((layout = H5Pget_layout(propid)) < 0) ERR;
	if (layout != H5D_COMPACT) ERR;
	if (H5Dread(datasetid, H5T_NATIVE_INT, H5S_ALL,
		    spaceid, H5P_DEFAULT, &data_in) < 0) ERR;

	/* Check the data. */
	if (data_in != data_out) ERR;

	if (H5Pclose(fapl_id) < 0 ||
	    H5Dclose(datasetid) < 0 ||
	    H5Pclose(propid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;
    }
    SUMMARIZE_ERR;
    printf("*** Checking that HDF5 does not allow chunked, scalar datasets...");
    {
	hid_t fapl_id, fcpl_id;
	hid_t datasetid;
	hid_t fileid, grpid, spaceid, plistid;
	hsize_t chunksize = 1;

	/* Create file, setting latest_format in access propertly list
	 * and H5P_CRT_ORDER_TRACKED in the creation property list. */
	if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) ERR;
	if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) ERR;
	if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
	if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) ERR;
	if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcpl_id, fapl_id)) < 0) ERR;

	if ((grpid = H5Gopen1(fileid, "/")) < 0) ERR;

	if ((spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;

	/* Create property list. */
	if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;

	/* Set chunking. */
	if (H5Pset_chunk(plistid, 1, &chunksize) < 0)ERR;

	/* Turn off error messages. The next call will generate a
	 * bunch of error messages on the console. */
	H5Eset_auto2(H5E_DEFAULT, NULL, NULL);

	/* Create the variable. This will not work, because only
	 * chunked datasets can use filters, and scalars can't be
	 * chunked. The H5Dcreate1() call will fail. */
	if ((datasetid = H5Dcreate1(grpid, SIMPLE_VAR_NAME1, H5T_NATIVE_INT,
				   spaceid, plistid)) > 0) ERR;

	/* Turn on error messages back on. */
	H5Eset_auto2(H5E_DEFAULT, (H5E_auto2_t)&H5Eprint1, stderr);

	if (H5Pclose(fapl_id) < 0 ||
	    H5Sclose(spaceid) < 0 ||
	    H5Gclose(grpid) < 0 ||
	    H5Fclose(fileid) < 0)
	    ERR;

    }
    SUMMARIZE_ERR;
    FINAL_RESULTS;
}
