/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**************************************************************
 *
 * tvattr.c
 *
 * This program tests routines in hdf/src/vattr.c.  Those routines
 *  set or change attributes for a vgroup, a vdata or a field of
 *  a vdata; get info about an attribute; read values of an attr.
 *
 * create_vset_stuff() creates 1 empty vgroup and 1 vgroup having 1
 *  vdata. write_vattr() adds attributes to the vgroups, vdata and
 *  the fields of the vdata. It then creates new vdata and vgroup,
 *  and adds attrs to them.  read_vattr reads the attributes back,
 *  and check their correctness.
 *
 * test_readattrtwice: tests the fix of bugzilla #486, which a
 *	subsequent read of an attribute failed. - BMR - Dec, 2005.
 *
 **************************************************************/
#include "hdf.h"
#include "tproto.h"
#include "vg.h"
#include <math.h>

#define FILENAME             "tvattr.hdf"
#define VGNAME0              "vgname0"
#define VGNAME1              "vgname1"
#define VGNAME2              "vgname2"
#define VSNAME0              "vsname0"
#define VSNAME1              "vsname1"
#define VSNAME2              "vsname2"
#define VSCLASS0             "vsclass0"
#define VGCLASS2             "vgclass2"
#define FLDNAME0             "fldname0"
#define FLDNAME1             "fldname1"
#define FLDNAME2             "fldname2"
#define FLDNAMES             "fldname0,fldname1"
#define FLDNAMES_1           "fldname1,fldname2"
#define N_RECS               3
#define ATTNAME1             "attname1"
#define ATTNAME2             "attname2"
#define ATTNAME3             "attname3"
#define ATTNAME4             "attname4"
#define ATTNAME5             "attname5"
#define ATTNAME6             "attname6"
#define ATTNAME7             "attname7"
#define ATTNAME8             "attname8"
#define ATTNAME9             "attname9"
#define ATTNAME10            "attname10"
#define EPS64                (float64)1.0E-14
#define EPS32                (float32)1.0E-7
#define MAX_HDF4_NAME_LENGTH 256

int32   data1[6] = {0, -1, 10, 11, 20, 21}, idata1[6];
char    data2[6] = {'A', 'B', 'C', 'D', 'E', 'F'}, idata2[6];
uint16  attr2[2] = {16, 32}, iattr2[2];
uint32  attr1[4] = {100, 132, 10032, 10064}, iattr1[2];
char    attr3[6] = {'m', 'N', 'p', 'S', 't', '\0'}, iattr3[6];
float32 attr4[2] = {(float32)32.001, (float32)-34.002}, iattr4[2];
float64 attr5[2] = {64.12345, -64.12345}, iattr5[2];

static intn create_vset_stuff(void);
static intn write_vattrs(void);
static intn read_vattrs(void);
static void test_readattrtwice(void);

/* create vdatas and vgroups */

static intn
create_vset_stuff(void)
{
    int32 fid, vgid, vsid;

    if (FAIL == (fid = Hopen(FILENAME, DFACC_CREATE, 0))) {
        num_errs++;
        return FAIL;
    }
    if (Vstart(fid) == FAIL) {
        num_errs++;
        return FAIL;
    }
    /* Vgroup Generation */
    if (FAIL == (vgid = (Vattach(fid, -1, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetname(vgid, VGNAME0)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        return FAIL;
    }
    /* create a vgroup and a vdata, insert the vdata into the vgroup */
    if (FAIL == (vgid = (Vattach(fid, -1, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetname(vgid, VGNAME1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = (VSattach(fid, -1, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetname(vsid, VSNAME1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSfdefine(vsid, FLDNAME1, DFNT_CHAR8, 1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSfdefine(vsid, FLDNAME2, DFNT_CHAR8, 1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetfields(vsid, FLDNAMES_1)) {
        num_errs++;
        return FAIL;
    }
    if (N_RECS != VSwrite(vsid, (unsigned char *)data2, N_RECS, FULL_INTERLACE)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vinsert(vgid, vsid)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        return FAIL;
    }
    /* close the file */
    if (FAIL == Vend(fid)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Hclose(fid)) {
        num_errs++;
        return FAIL;
    }
    return SUCCEED;
} /* create_vset_stuff */

/* test attribute routines */
static intn
write_vattrs(void)
{
    int32 fid, vgid, vsid;
    int32 vsref, vgref;
    int32 fldindex, vsversion;
    intn  n_flds;

    /* add attrs to the 1 vg */
    if (FAIL == (fid = Hopen(FILENAME, DFACC_RDWR, -1))) {
        num_errs++;
        return FAIL;
    }
    if (Vstart(fid) == FAIL) {
        num_errs++;
        return FAIL;
    }

    if (FAIL == (vgref = Vgetid(fid, -1))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vgid = Vattach(fid, vgref, "w"))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetattr(vgid, ATTNAME1, DFNT_UINT32, 2, attr1)) {
        num_errs++;
        printf(">>> Vsetattr1 failed\n");
    }
    /* change data type of existing attr, should fail */
    if (FAIL != Vsetattr(vgid, ATTNAME1, DFNT_UINT16, 2, attr2)) {
        num_errs++;
        printf(">>> Vsetattr1 changes attr type, should failed\n");
    }
    /* change order of existing attr, should fail */
    if (FAIL != Vsetattr(vgid, ATTNAME1, DFNT_UINT32, 1, attr1)) {
        num_errs++;
        printf(">>> Vsetattr changes attr order, should failed\n");
    }
    /* change values of existing attr */
    if (FAIL == Vsetattr(vgid, ATTNAME1, DFNT_UINT32, 2, &attr1[2])) {
        num_errs++;
        printf(">>> Vsetattr failed in changing attr values.\n");
    }

    if (FAIL == Vsetattr(vgid, ATTNAME2, DFNT_UINT16, 2, attr2)) {
        num_errs++;
        printf(">>> Vsetattr2 failed\n");
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        return FAIL;
    }
    /* add attr to vdata */
    if (FAIL == (vsref = VSfind(fid, VSNAME1))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = VSattach(fid, vsref, "w"))) {
        num_errs++;
        return FAIL;
    }
    if (VSET_VERSION != (vsversion = VSgetversion(vsid))) {
        num_errs++;
        printf(">>> Wrong version, should be 3, got %d \n", (int)vsversion);
    }
    /* check number of fields */
    if (2 != (n_flds = VFnfields(vsid))) {
        num_errs++;
        printf(">>> Wrong number of fields, should be 2, got %d.\n", n_flds);
    }
    /* search for non-existing field  */
    if (FAIL != VSfindex(vsid, FLDNAME0, &fldindex)) {
        num_errs++;
        printf(">>> Search for non-existing field, should fail.\n");
    }
    if (FAIL == VSsetattr(vsid, _HDF_VDATA, ATTNAME3, DFNT_CHAR8, 3, attr3)) {
        num_errs++;
        printf(">>> VSsetattr3 failed\n");
    }
    if (FAIL == VSfindex(vsid, FLDNAME1, &fldindex) || fldindex != 0) {
        num_errs++;
        printf(">>> VSfindex  failed in search for FLDNAME1 .\n");
    }
    if (FAIL == VSsetattr(vsid, 0, ATTNAME4, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr4 failed\n");
    }
    if (FAIL == VSfindex(vsid, FLDNAME2, &fldindex) || fldindex != 1) {
        num_errs++;
        printf(">>> VSfindex  failed in search for FLDNAME2 .\n");
    }
    if (FAIL == VSsetattr(vsid, 1, ATTNAME5, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr5 failed\n");
    }
    if (FAIL != VSsetattr(vsid, 2, ATTNAME3, DFNT_CHAR8, 5, attr3)) {
        num_errs++;
        printf(">>> Set attr for non-existing field, should fail\n");
    }
    if (FAIL != VSsetattr(vsid, -2, ATTNAME3, DFNT_CHAR8, 5, attr3)) {
        num_errs++;
        printf(">>> Set attr for non-existing field, should fail\n");
    }

    /* set same attr name to different fields */
    if (FAIL == VSsetattr(vsid, _HDF_VDATA, ATTNAME4, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr6 failed\n");
    }
    if (FAIL == VSsetattr(vsid, 0, ATTNAME5, DFNT_FLOAT64, 1, attr5)) {
        num_errs++;
        printf(">>> VSsetattr5 failed\n");
    }
    /* create an attribute with the same name as an existing vdata */
    if (FAIL == VSsetattr(vsid, 0, VSNAME1, DFNT_FLOAT64, 1, attr5)) {
        num_errs++;
        printf(">>> VSsetattr7 failed\n");
    }
    if (VSET_NEW_VERSION != (vsversion = VSgetversion(vsid))) {
        num_errs++;
        printf(">>> Wrong version, should be 4, got %d \n", (int)vsversion);
    }
    /* change datatype of existing attr, should fail */
    if (FAIL != VSsetattr(vsid, 0, ATTNAME5, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr changes attr type, should fail.\n");
    }
    /* change order of existing attr, should fail */
    if (FAIL != VSsetattr(vsid, 0, ATTNAME5, DFNT_FLOAT64, 2, attr5)) {
        num_errs++;
        printf(">>> VSsetattr changes attr order, should fail.\n");
    }
    /* change values of existing attr */
    if (FAIL == VSsetattr(vsid, 0, ATTNAME5, DFNT_FLOAT64, 1, &attr5[1])) {
        num_errs++;
        printf(">>> VSsetattr failed in changing attr values.\n");
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        return FAIL;
    }

    /* create lone vdata  and add attributes to it */
    if (FAIL == (vsid = (VSattach(fid, -1, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetname(vsid, VSNAME0)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSfdefine(vsid, FLDNAME0, DFNT_INT32, 1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSfdefine(vsid, FLDNAME1, DFNT_INT32, 1)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetfields(vsid, FLDNAMES)) {
        num_errs++;
        return FAIL;
    }
    if (N_RECS != VSwrite(vsid, (unsigned char *)data1, N_RECS, FULL_INTERLACE)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSfindex(vsid, FLDNAME0, &fldindex)) {
        num_errs++;
        printf(">>> VSfindex failed in searching for FLDNAME0.\n");
    }
    if (FAIL == VSsetattr(vsid, 0, ATTNAME6, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr6 failed\n");
    }

    if (FAIL == VSsetattr(vsid, _HDF_VDATA, ATTNAME7, DFNT_CHAR8, 3, attr3)) {
        num_errs++;
        printf(">>> VSsetattr7 failed\n");
    }
    if (FAIL == VSfindex(vsid, FLDNAME1, &fldindex) || fldindex != 1) {
        num_errs++;
        printf(">>> VSfindex  failed in searching for FLDNAME1.\n");
    }
    if (FAIL == VSsetattr(vsid, 0, ATTNAME8, DFNT_FLOAT32, 1, attr4)) {
        num_errs++;
        printf(">>> VSsetattr8 failed\n");
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        return FAIL;
    }
    /* attach again, and modify attr */
    if (FAIL == (vsref = VSfind(fid, VSNAME0))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = VSattach(fid, vsref, "w"))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetclass(vsid, VSCLASS0)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == VSsetattr(vsid, 1, ATTNAME8, DFNT_FLOAT32, 1, &attr4[1])) {
        num_errs++;
        printf(">>> VSsetattr failed in modifying attr8.\n");
    }
    if (FAIL == VSsetattr(vsid, 0, ATTNAME9, DFNT_CHAR8, 5, attr3)) {
        num_errs++;
        printf(">>> VSsetattr9  field. \n");
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        return FAIL;
    }
    /* attach again with "r" access to test VSsetattr on "r" access vdata
       BMR - Nov 4, 2004 */
    if (FAIL == (vsref = VSfind(fid, VSNAME0))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = VSattach(fid, vsref, "r"))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL != VSsetattr(vsid, 1, "NO ATTRIBUTE", DFNT_FLOAT32, 1, &attr4[1])) {
        num_errs++;
        printf(">>> VSsetattr did not fail on read access vdata.\n");
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        return FAIL;
    }
    /* create vgroup and add attrs */
    if (FAIL == (vgid = (Vattach(fid, -1, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetname(vgid, VGNAME2)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vaddtagref(vgid, DFTAG_VH, vsref)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetclass(vgid, VGCLASS2)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        return FAIL;
    }
    /* attach again, add attr */
    if (FAIL == (vgref = Vfind(fid, VGNAME2))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vgid = (Vattach(fid, vgref, "w")))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Vsetattr(vgid, ATTNAME9, DFNT_UINT32, 1, attr1)) {
        num_errs++;
        printf(">>> Vsetattr1 failed\n");
    }
    /* change data type of existing attr, should fail */
    if (FAIL != Vsetattr(vgid, ATTNAME9, DFNT_UINT16, 1, attr2)) {
        num_errs++;
        printf(">>> Vsetattr changes attr type, should failed\n");
    }
    if (FAIL == Vsetattr(vgid, ATTNAME10, DFNT_UINT16, 2, attr2)) {
        num_errs++;
        printf(">>> Vsetattr1 failed\n");
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        printf(">>> Vdetach failed in vgname2.\n");
    }

    if (FAIL == Vend(fid)) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == Hclose(fid)) {
        num_errs++;
        return FAIL;
    }
    return SUCCEED;
} /* write_vattr */

/*  Test reading routines */
static intn
read_vattrs(void)
{
    int32 fid, vgid, vsid, vgref, vsref;
    intn  n_vgattrs, n_vsattrs, n_fldattrs;
    intn  iattrindex, ret;
    int32 i_type, i_count, i_size, iversion;
    char  iattrname[FIELDNAMELENMAX + 1];

    if (FAIL == (fid = Hopen(FILENAME, DFACC_RDONLY, 0))) {
        num_errs++;
        return FAIL;
    }
    if (Vstart(fid) == FAIL) {
        num_errs++;
        return FAIL;
    }
    /* Read vgroup attrs first */
    if (FAIL == (vgref = Vfind(fid, VGNAME0))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vgid = (Vattach(fid, vgref, "r")))) {
        num_errs++;
        return FAIL;
    }
    if ((iversion = Vgetversion(vgid)) < VSET_NEW_VERSION) {
        num_errs++;
        printf(">>> Wrong Vgroup version, should be %d, got %d.\n", VSET_NEW_VERSION, (int)iversion);
    }
    if (FAIL == (n_vgattrs = Vnattrs(vgid)) || n_vgattrs != 2) {
        num_errs++;
        printf(">>> Wrong num of Vgroup0 attrs, should be %d, got %d.\n", 2, n_vgattrs);
    }
    if (0 != (iattrindex = Vfindattr(vgid, ATTNAME1))) {
        num_errs++;
        printf(">>> attname1 should be 0th attr of vgname0, ");
        printf("not %d.\n", iattrindex);
    }
    if (FAIL == Vattrinfo(vgid, 0, iattrname, &i_type, &i_count, &i_size) ||
        strncmp(iattrname, ATTNAME1, strlen(ATTNAME1)) != 0 || i_type != DFNT_UINT32 || i_count != 2 ||
        i_size != i_count * DFKNTsize(DFNT_UINT32 | DFNT_NATIVE)) {
        num_errs++;
        printf(">>> Wrong attrinfo for attname1 of vgname0; \
             got %s %d %d %d.\n",
               iattrname, (int)i_type, (int)i_count, (int)i_size);
    }
    if (FAIL == Vgetattr(vgid, 0, iattr1) || iattr1[0] != attr1[2] || iattr1[1] != attr1[3]) {
        num_errs++;
        printf(">>> Wrong values for attname1 of vgname0; ");
        printf("got %u %u, should be %u %u.\n", (unsigned)iattr1[0], (unsigned)iattr1[1], (unsigned)attr1[2],
               (unsigned)attr1[3]);
    }

    if (FAIL == Vattrinfo(vgid, 1, iattrname, &i_type, &i_count, &i_size) ||
        strncmp(iattrname, ATTNAME2, strlen(ATTNAME2)) != 0 || i_type != DFNT_UINT16 || i_count != 2 ||
        i_size != i_count * DFKNTsize(DFNT_UINT16 | DFNT_NATIVE)) {
        num_errs++;
        printf(">>> Wrong attrinfo for attname2 of vgname0; \
            got %s %d %d %d.\n",
               iattrname, (int)i_type, (int)i_count, (int)i_size);
    }
    if (FAIL == Vgetattr(vgid, 1, iattr2) || iattr2[0] != attr2[0] || iattr2[1] != attr2[1]) {
        num_errs++;
        printf(">>> Wrong values for attname2 of vgname0; \
                     got %u %u, should be %u %u.\n",
               iattr2[0], iattr2[1], attr2[0], attr2[1]);
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        printf(">>>Vdetach failed in vgname0.\n");
    }
    /* VGNAME1 has no attr */
    if (FAIL == (vgref = Vfind(fid, VGNAME1))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vgid = (Vattach(fid, vgref, "r")))) {
        num_errs++;
        return FAIL;
    }
    if ((iversion = Vgetversion(vgid)) != VSET_VERSION) {
        num_errs++;
        printf(">>> Wrong Vgroup version, should be %d, got %d.\n", VSET_VERSION, (int)iversion);
    }
    if (FAIL == (n_vgattrs = Vnattrs(vgid)) || n_vgattrs != 0) {
        num_errs++;
        printf(">>> Wrong num of Vgroup1 attrs, should be %d, got %d.\n", 0, n_vgattrs);
    }
    if (FAIL == Vdetach(vgid)) {
        num_errs++;
        printf(">>>Vdetach failed in detaching vgname1.\n");
    }
    /* VSNAME0 has 5 attrs */
    if (FAIL == (vsref = VSfind(fid, VSNAME0))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = (VSattach(fid, vsref, "r")))) {
        num_errs++;
        return FAIL;
    }
    if ((iversion = VSgetversion(vsid)) != VSET_NEW_VERSION) {
        num_errs++;
        printf(">>> Wrong Vdata version, should be %d, got %d.\n", VSET_NEW_VERSION, (int)iversion);
    }
    if (FAIL == (n_vsattrs = VSnattrs(vsid)) || n_vsattrs != 5) {
        num_errs++;
        printf(">>> Wrong num of Vsname0 attrs, should be %d, got %d.\n", 5, n_vsattrs);
    }
    /* get num of attrs of fld 1 */
    if (FAIL == (n_fldattrs = VSfnattrs(vsid, 1)) || n_fldattrs != 1) {
        num_errs++;
        printf(">>> Wrong num of Vsname0 fld 1 attrs, ");
        printf("should be %d, got %d.\n ", 1, n_vsattrs);
    }
    /* read the 3rd attr of fld 0. The attr is char type. */
    if ((FAIL == VSattrinfo(vsid, 0, 2, iattrname, &i_type, &i_count, &i_size)) ||
        (strcmp(iattrname, ATTNAME9) != 0) || (i_type != DFNT_CHAR8) || (i_count != 5) || (i_size != 5)) {
        num_errs++;
        printf(">>> Wrong attrinfo for attname9 of vsname0 fld0; ");
        printf(" got  %s %d %d %d.\n", iattrname, (int)i_type, (int)i_count, (int)i_size);
    }
    if (FAIL == VSgetattr(vsid, 0, 2, iattr3) || iattr3[0] != attr3[0] || iattr3[1] != attr3[1] ||
        iattr3[2] != attr3[2] || iattr3[3] != attr3[3] || iattr3[4] != attr3[4]) {
        num_errs++;
        printf(">>> Wrong values for attname9  of vsname0; \
                     got %5s, should be %5s.\n",
               iattr3, attr3);
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        printf(">>>Vsdetach failed in vsname0.\n");
    }
    /* VSNAME1 has 2 attrs, fld0  has 3 and fld1 has 1 attr */
    if (FAIL == (vsref = VSfind(fid, VSNAME1))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = (VSattach(fid, vsref, "r")))) {
        num_errs++;
        return FAIL;
    }
    if ((iversion = VSgetversion(vsid)) != VSET_NEW_VERSION) {
        num_errs++;
        printf(">>> Wrong Vdata version, should be %d, got %d.\n", VSET_NEW_VERSION, (int)iversion);
    }
    if (FAIL == (n_vsattrs = VSnattrs(vsid)) || n_vsattrs != 6) {
        num_errs++;
        printf(">>> Wrong num of Vsname1 attrs, should be %d, ", 6);
        printf("got %d.\n", n_vsattrs);
    }
    if (FAIL == (n_fldattrs = VSfnattrs(vsid, _HDF_VDATA)) || n_fldattrs != 2) {
        num_errs++;
        printf(">>> Wrong num of Vsname1 vdata attrs, ");
        printf("should be %d, got %d.\n ", 2, n_fldattrs);
    }
    /* look for non-existing attr, should fail */
    if (FAIL != (iattrindex = VSfindattr(vsid, _HDF_VDATA, ATTNAME9))) {
        num_errs++;
        printf(">>> attname9 is not an attr of vdata vsname1, ");
        printf(" should fail.\n");
    }
    /* use wrong findex, should fail */
    if (FAIL != (iattrindex = VSfindattr(vsid, 3, ATTNAME9))) {
        num_errs++;
        printf(">>> Vdata vsname1 has only 2 fields, ");
        printf(" should fail.\n");
    }
    /* use wrong findex, should fail */
    if (FAIL != VSattrinfo(vsid, 4, 0, NULL, &i_type, &i_count, &i_size)) {
        num_errs++;
        printf(">>> Vdata vsname1 has only 2 fields, should fail.\n");
    }
    /* use wrong attrindex, should fail */
    if (FAIL != VSattrinfo(vsid, 1, 3, iattrname, &i_type, &i_count, NULL)) {
        num_errs++;
        printf(">>> Field1 of vsname1 has only 1 attr, should fail.\n");
    }
    /* use wrong findex, should fail */
    if (FAIL != VSgetattr(vsid, 4, 0, iattr1)) {
        num_errs++;
        printf(">>> Vdata vsname1 has only 2 fields, should fail.\n");
    }
    /* use wrong attrindex, should fail */
    if (FAIL != VSgetattr(vsid, 1, 3, iattr1)) {
        num_errs++;
        printf(">>> Field1 of vsname1 has only 1 attr, should fail.\n");
    }

    /* get the 2nd attr  */
    if ((FAIL == (iattrindex = VSfindattr(vsid, _HDF_VDATA, ATTNAME4))) || (iattrindex != 1)) {
        num_errs++;
        printf(">>> attname4 should be index 1 of vsname1, not %d.\n", iattrindex);
    }
    if ((FAIL == VSattrinfo(vsid, _HDF_VDATA, iattrindex, iattrname, &i_type, &i_count, &i_size)) ||
        (strcmp(iattrname, ATTNAME4) != 0) || (i_type != DFNT_FLOAT32) || (i_count != 1) ||
        (i_size != DFKNTsize(DFNT_FLOAT | DFNT_NATIVE))) {
        num_errs++;
        printf(">>> Wrong attrinfo for attname4 of vdata vsname1; ");
        printf(" got  %s %d %d.\n", iattrname, (int)i_type, (int)i_count);
    }
    if (FAIL == VSgetattr(vsid, _HDF_VDATA, 1, iattr4) ||
        (fabs((double)(iattr4[0] - attr4[0])) > fabs((double)(attr4[0] * EPS32)))) {
        num_errs++;
        printf(">>> Wrong values for attname4  of vsname1; \
                     got %f, should be %f.\n",
               (double)iattr4[0], (double)attr4[0]);
    }
    if (FALSE != VSisattr(vsid)) {
        num_errs++;
        printf(">>> VSisattr failed. Vsname1 is not attribute vdata.\n");
    }
    /* get  the 3rd attr of fld0. The attr name is VSNAME1 */
    if ((FAIL == (iattrindex = VSfindattr(vsid, 0, VSNAME1))) || (iattrindex != 2)) {
        num_errs++;
        printf(">>> VSNAME1 should be index 2 of fld 0 of vsname1,");
        printf("  not %d.\n", iattrindex);
    }
    if ((FAIL == VSattrinfo(vsid, 0, iattrindex, iattrname, &i_type, &i_count, &i_size)) ||
        (strcmp(iattrname, VSNAME1) != 0) || (i_type != DFNT_FLOAT64) || (i_count != 1) ||
        (i_size != DFKNTsize(DFNT_FLOAT64 | DFNT_NATIVE))) {
        num_errs++;
        printf(">>> Wrong attrinfo for VSNAME1 of fld 0 of vdata vsname1; ");
        printf(" got  %s %d %d.\n", iattrname, (int)i_type, (int)i_count);
    }
    if (FAIL == VSgetattr(vsid, 0, 2, iattr5) ||
        (fabs((double)(iattr5[0] - attr5[0])) > fabs((double)(attr5[0] * EPS64)))) {
        num_errs++;
        printf(">>> Wrong values for attr VSNAME1  of fld 0 of vsname1; \
                     got %f, should be %f.\n",
               iattr5[0], attr5[0]);
    }
    if (FAIL == VSdetach(vsid)) {
        num_errs++;
        printf(">>>VSdetach failed in vsname1.\n");
    }
    /* test VSisattr for attr vdata */
    if (FAIL == (vsref = VSfind(fid, ATTNAME10))) {
        num_errs++;
        return FAIL;
    }
    if (FAIL == (vsid = (VSattach(fid, vsref, "r")))) {
        num_errs++;
        return FAIL;
    }
    if (TRUE != VSisattr(vsid)) {
        num_errs++;
        printf(">>> VSisattr failed. ATTNAME10 is an attribute vdata.\n");
    }
    if (VSET_VERSION != (iversion = VSgetversion(vsid))) {
        num_errs++;
        printf(">>> Wrong vdata version. ATTNAME10 should be of ");
        printf(" %d, got %d\n", VSET_VERSION, (int)iversion);
    }
    ret = VSdetach(vsid);
    CHECK(ret, FAIL, "VSdetach");
    ret = Vend(fid);
    CHECK(ret, FAIL, "Vend");
    ret = Hclose(fid);
    CHECK(ret, FAIL, "Hclose");

    return 0;
}

static void
test_readattrtwice(void)
{
    int32 file_id, vsref, vsid;
    int32 findex, fattr_index;
    int32 data_type, count, size;
    int32 nfields, num_attrs, num_fattrs;
    char  name[MAX_HDF4_NAME_LENGTH + 1];
    char *buffer;
    int   k;
    intn  ret;

    file_id = Hopen(FILENAME, DFACC_READ, 0);
    CHECK_VOID(file_id, FAIL, "Hopen:FILENAME");

    ret = Vstart(file_id);
    CHECK_VOID(ret, FAIL, "Vstart:file_id");

    /* get the first vdata */
    vsref = VSgetid(file_id, -1);
    if (vsref == FAIL) {
        num_errs++;
        printf(">>> VSgetid was unable to find first Vdata\n");
    }

    /* read attributes of each vdata and its fields, then go to next vdata */
    while (vsref != -1) {
        vsid = VSattach(file_id, vsref, "r");
        CHECK_VOID(vsid, FAIL, "VSattach");

        num_attrs = VSfnattrs(vsid, _HDF_VDATA);
        CHECK_VOID(num_attrs, FAIL, "VSfnattrs");

        for (k = 0; k < num_attrs; k++) {
            ret = VSattrinfo(vsid, _HDF_VDATA, k, name, &data_type, &count, &size);
            CHECK_VOID(ret, FAIL, "VSattrinfo");

            buffer = malloc(size + 1);
            CHECK_VOID(buffer, NULL, "malloc");

            ret = VSgetattr(vsid, _HDF_VDATA, k, buffer);
            CHECK_VOID(ret, FAIL, "VSgetattr");

            ret = VSgetattr(vsid, _HDF_VDATA, k, buffer);
            if (ret == FAIL) {
                num_errs++;
                printf(">>> Reading attribute twice failed - (bugzilla 486)\n");
            }
            free(buffer);

            nfields = VFnfields(vsid);
            CHECK_VOID(nfields, FAIL, "VFnfields");

            for (findex = 0; findex < nfields; findex++) {
                num_fattrs = VSfnattrs(vsid, findex);
                CHECK_VOID(num_fattrs, FAIL, "VSfnattrs");

                for (fattr_index = 0; fattr_index < num_fattrs; fattr_index++) {
                    ret = VSattrinfo(vsid, findex, fattr_index, name, &data_type, &count, &size);
                    CHECK_VOID(ret, FAIL, "VSattrinfo");

                    buffer = malloc(size);
                    CHECK_VOID(buffer, NULL, "malloc");

                    ret = VSgetattr(vsid, findex, fattr_index, buffer);
                    CHECK_VOID(ret, FAIL, "VSgetattr");

                    ret = VSgetattr(vsid, findex, fattr_index, buffer);
                    if (ret == FAIL) {
                        num_errs++;
                        printf(">>> Reading attribute twice failed - (bugzilla 486)\n");
                    }

                    free(buffer);
                } /* for fattr_index */
            }     /* for findex */
        }         /* for k */

        ret = VSdetach(vsid);
        CHECK_VOID(ret, FAIL, "VSdetach");

        /* find next vdata */
        vsref = VSgetid(file_id, vsref);
    }
    ret = Vend(file_id);
    CHECK_VOID(ret, FAIL, "VSdetach");
    ret = Hclose(file_id);
    CHECK_VOID(ret, FAIL, "Hclose");
} /* test_readattrtwice */

/* main test driver */
void
test_vset_attr(void)
{
    create_vset_stuff();
    write_vattrs();
    read_vattrs();
    test_readattrtwice();
} /* test_vset_attr */
