#include "hdf5.h" #include "api.h" #include "buffer.h" #include #include #ifdef _WIN32 #pragma warning(disable: 4018) #endif #define HDF_TYPE 'H5' #define BUFF_SIZE 1024 #pragma warning(disable: 4244) class zsRegPrimitive { public: zsRegPrimitive(const char* name, int type, void* func) { api_add_primitive(name, type, func); } }; class zsHDF { size_t size; public: zsHDF() : fid(-1), gid(-1), did(-1), tid(-1), flag(false), ndim(0), size(0), ptr(0) { } ~zsHDF() { if (tid > 0) H5Tclose(tid); if (did > 0) H5Dclose(did); if (gid > 0) H5Gclose(gid); if (fid > 0) H5Fclose(fid); if (ptr) free(ptr); } void checksize(size_t size) { if (this->size < size || this->size > 2*size) { if (ptr) { free(ptr); ptr = 0; } ptr = malloc(size); this->size = size; } } hid_t fid, gid, did, tid; hsize_t dims[H5S_MAX_RANK]; size_t ndim, dsize, tsize; bool flag; // true if dataset is the target; otherwise group is the target. int type; void *ptr; }; enum { HDF_CHAR, HDF_UCHAR, HDF_SHORT, HDF_USHORT, HDF_INT, HDF_UINT, HDF_FLOAT, HDF_DOUBLE }; ///////////////////////////////////////////////////////////////////// void input_error(void* caller) { api_runtime_error(caller, "bad arguments"); } void check_dataset(void* caller, zsHDF *o) { if (!o->flag) api_runtime_error(caller, "dataset not specified"); } void type_error(void* caller) { api_runtime_error(caller, "unsupported variable/attibute type"); } void hdf_destroy(void *ptr) { delete (zsHDF*)ptr; } herr_t hdf_error(void *data) { H5Eclear(); return 1; } ///////////////////////////////////////////////////////////////////// void* hdf_open(void *caller, int nargs, void** args) { if (nargs < 1) input_error(caller); const char *fname = api_get_string(caller, args[0]); zsHDF *o = new zsHDF; H5Eset_auto(hdf_error, o); if (nargs > 1) { const char *s = api_get_string(caller, args[1]); if (s[0] == 'w' || s[0] == 'W') o->fid = H5Fopen(fname, H5F_ACC_RDWR, H5P_DEFAULT); else if (s[0] == 'c' || s[0] == 'C') o->fid = H5Fcreate(fname, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); else o->fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); } else { o->fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); } if (o->fid < 0) { api_runtime_error(caller, "failed to open or create HDF file"); } o->gid = H5Gopen(o->fid, "/"); if (o->gid < 0) o->gid = H5Gcreate(o->fid, "/", 1); if (o->gid < 0) api_runtime_error(caller, "failed to open or create group"); return api_create_user(caller, o, 0, hdf_destroy, HDF_TYPE); } static zsRegPrimitive hdf0("hdf", 0, hdf_open); void* hdf_version(void *caller, int nargs, void** args) { unsigned v1, v2, v3; H5get_libversion(&v1, &v2, &v3); static char buf[64]; sprintf(buf, "version-%d.%d.%d", v1, v2, v3); return api_create_string(caller, buf); } static zsRegPrimitive hdf1("version", HDF_TYPE, hdf_version); void* hdf_group(void *caller, int nargs, void** args) { if (nargs < 2) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); const char *name = api_get_string(caller, args[1]); if (o->gid >= 0) H5Gclose(o->gid); o->gid = H5Gopen(o->fid, name); if (o->gid < 0) o->gid = H5Gcreate(o->fid, name, strlen(name)); if (o->gid < 0) api_runtime_error(caller, "failed to open/create group"); o->flag = false; return 0; } static zsRegPrimitive hdf2("group", HDF_TYPE, hdf_group); void* hdf_dataset(void *caller, int nargs, void** args) { if (nargs < 2) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); const char *name = api_get_string(caller, args[1]); if (nargs == 2) { // set dataset target if (o->did >= 0) H5Dclose(o->did); o->did = H5Dopen(o->gid, name); if (o->did < 0) return api_create_integer(caller, 0); hid_t dspace = H5Dget_space(o->did); if (dspace < 0) api_runtime_error(caller, "failed to get dataset space"); o->ndim = H5Sget_simple_extent_dims(dspace, o->dims, 0); H5Sclose(dspace); if (o->tid >= 0) H5Tclose(o->tid); o->tid = H5Dget_type(o->did); if (H5Tequal(o->tid, H5T_NATIVE_CHAR) > 0) { o->tsize = sizeof(char); o->type = HDF_CHAR; } else if (H5Tequal(o->tid, H5T_NATIVE_UCHAR) > 0) { o->tsize = sizeof(unsigned char); o->type = HDF_UCHAR; } else if (H5Tequal(o->tid, H5T_NATIVE_SHORT) > 0) { o->tsize = sizeof(short); o->type = HDF_SHORT; } else if (H5Tequal(o->tid, H5T_NATIVE_USHORT) > 0) { o->tsize = sizeof(unsigned short); o->type = HDF_USHORT; } else if (H5Tequal(o->tid, H5T_NATIVE_INT) > 0) { o->tsize = sizeof(int); o->type = HDF_INT; } else if (H5Tequal(o->tid, H5T_NATIVE_UINT) > 0) { o->tsize = sizeof(unsigned int); o->type = HDF_UINT; } else if (H5Tequal(o->tid, H5T_NATIVE_FLOAT) > 0) { o->tsize = sizeof(float); o->type = HDF_FLOAT; } else if (H5Tequal(o->tid, H5T_NATIVE_DOUBLE) > 0) { o->tsize = sizeof(double); o->type = HDF_DOUBLE; } else { type_error(caller); } o->flag = true; o->dsize = 1; for (size_t i = 0; i < o->ndim; i++) o->dsize *= o->dims[i]; return api_create_integer(caller, 1); } // define dataset if (nargs < 4) input_error(caller); const char *type = api_get_string(caller, args[2]); if (o->tid >= 0) H5Tclose(o->tid); if (!strcmp(type, "char")) { o->tid = H5Tcopy(H5T_NATIVE_CHAR); o->tsize = sizeof(char); o->type = HDF_CHAR; } else if (!strcmp(type, "uchar")) { o->tid = H5Tcopy(H5T_NATIVE_UCHAR); o->tsize = sizeof(unsigned char); o->type = HDF_UCHAR; } else if (!strcmp(type, "short")) { o->tid = H5Tcopy(H5T_NATIVE_SHORT); o->tsize = sizeof(short); o->type = HDF_SHORT; } else if (!strcmp(type, "ushort")) { o->tid = H5Tcopy(H5T_NATIVE_USHORT); o->tsize = sizeof(unsigned short); o->type = HDF_USHORT; } else if (!strcmp(type, "int")) { o->tid = H5Tcopy(H5T_NATIVE_INT); o->tsize = sizeof(int); o->type = HDF_INT; } else if (!strcmp(type, "uint")) { o->tid = H5Tcopy(H5T_NATIVE_UINT); o->tsize = sizeof(unsigned int); o->type = HDF_UINT; } else if (!strcmp(type, "float")) { o->tid = H5Tcopy(H5T_NATIVE_FLOAT); o->tsize = sizeof(float); o->type = HDF_FLOAT; } else if (!strcmp(type, "double")) { o->tid = H5Tcopy(H5T_NATIVE_DOUBLE); o->tsize = sizeof(double); o->type = HDF_DOUBLE; } else { input_error(caller); } o->ndim = 0; o->dsize = 1; for (int i = 3; i < nargs && o->ndim < H5S_MAX_RANK; i++) { integer_t n = api_get_integer(caller, args[i]); if (n <= 0) input_error(caller); o->dims[o->ndim] = n; o->dsize *= n; o->ndim++; } hid_t dspace = H5Screate_simple(nargs-3, o->dims, 0); if (dspace < 0) api_runtime_error(caller, "failed to create data space"); if (o->did >= 0) H5Dclose(o->did); o->did = H5Dcreate(o->gid, name, o->tid, dspace, H5P_DEFAULT); H5Sclose(dspace); if (o->did < 0) api_runtime_error(caller, "failed to create dataset"); o->flag = true; return 0; } static zsRegPrimitive hdf3("dataset", HDF_TYPE, hdf_dataset); void* hdf_size(void *caller, int nargs, void** args) { if (nargs < 1) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); check_dataset(caller, o); void *arr = api_create_array(caller, 3); api_set_array_object(caller, arr, "0", api_create_integer(caller, o->dsize)); api_set_array_object(caller, arr, "1", api_create_integer(caller, o->tsize)); switch (o->type) { case HDF_CHAR: api_set_array_object(caller, arr, "2", api_create_string(caller, "char")); break; case HDF_UCHAR: api_set_array_object(caller, arr, "2", api_create_string(caller, "uchar")); break; case HDF_SHORT: api_set_array_object(caller, arr, "2", api_create_string(caller, "short")); break; case HDF_USHORT: api_set_array_object(caller, arr, "2", api_create_string(caller, "ushort")); break; case HDF_INT: api_set_array_object(caller, arr, "2", api_create_string(caller, "int")); break; case HDF_UINT: api_set_array_object(caller, arr, "2", api_create_string(caller, "uint")); break; case HDF_FLOAT: api_set_array_object(caller, arr, "2", api_create_string(caller, "float")); break; case HDF_DOUBLE: api_set_array_object(caller, arr, "2", api_create_string(caller, "double")); break; default: type_error(caller); } return arr; } static zsRegPrimitive hdf4("size", HDF_TYPE, hdf_size); void* hdf_dims(void *caller, int nargs, void** args) { if (nargs < 1) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); check_dataset(caller, o); void *arr = api_create_array(caller, o->ndim); for (int i = 0; i < o->ndim; i++) api_set_array_object2(caller, arr, i, api_create_integer(caller, o->dims[i])); return arr; } static zsRegPrimitive hdf5("dims", HDF_TYPE, hdf_dims); void* hdf_getatt(void *caller, int nargs, void** args) { if (nargs < 2) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); const char *name = api_get_string(caller, args[1]); hid_t id = o->did; if (!o->flag) id = o->gid; hid_t att_id = H5Aopen_name(id, name); if (att_id < 0) return 0; // return null if the attribute does not exist. hid_t att_type = H5Aget_type(att_id); if (att_type < 0) { H5Aclose(att_id); return 0; } hid_t att_space = H5Aget_space(att_id); if (att_space < 0) { H5Aclose(att_id); H5Sclose(att_space); return 0; } void *ret = 0; int ndim = H5Sget_simple_extent_ndims(att_space); if (ndim == 0) { switch (H5Tget_class(att_type)) { case H5T_INTEGER: { int value; if (H5Aread(att_id, H5T_NATIVE_INT, &value) >= 0) ret = api_create_integer(caller, value); } break; case H5T_FLOAT: { double value; if (H5Aread(att_id, H5T_NATIVE_DOUBLE, &value) >= 0) ret = api_create_real(caller, value); } break; case H5T_STRING: { zsBuffer buf(1024); hid_t atype = H5Tcopy(H5T_C_S1); H5Tset_size(atype, 1023); if (H5Aread(att_id, atype, buf.u.pchar) >= 0) { buf.u.pchar[1023] = 0; ret = api_create_string(caller, buf.u.pchar); } H5Tclose(atype); } break; default: type_error(caller); break; } } else if (ndim == 1) { hsize_t dims[1]; if (H5Sget_simple_extent_dims(att_space, dims, NULL) == 1) { switch (H5Tget_class(att_type)) { case H5T_INTEGER: { zsBuffer buf(dims[0]*sizeof(int)); if (H5Aread(att_id, H5T_NATIVE_INT, buf.u.ptr) >= 0) { ret = api_create_array(caller, dims[0]); for (int i = 0; i < dims[0]; i++) { api_set_array_object2(caller, ret, i, api_create_integer(caller, buf.u.pint[i])); } } } break; case H5T_FLOAT: { zsBuffer buf(dims[0]*sizeof(double)); if (H5Aread(att_id, H5T_NATIVE_DOUBLE, buf.u.ptr) >= 0) { ret = api_create_array(caller, dims[0]); for (int i = 0; i < dims[0]; i++) { api_set_array_object2(caller, ret, i, api_create_real(caller, buf.u.pdouble[i])); } } } break; default: type_error(caller); } } } H5Aclose(att_id); H5Tclose(att_type); H5Sclose(att_space); return ret; } void* hdf_putatt(void *caller, int nargs, void** args) { if (nargs < 3) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); const char *name = api_get_string(caller, args[1]); hid_t id = o->did; if (!o->flag) id = o->gid; H5Adelete(id, name); hid_t status = -1; if (api_is_real(args[2])) { // e.g., hdf.name = 1.23; double value = api_get_real(caller, args[2]); hid_t space = H5Screate(H5S_SCALAR); hid_t aid = H5Acreate(id, name, H5T_NATIVE_DOUBLE, space, H5P_DEFAULT); if (aid > 0) { status = H5Awrite(aid, H5T_NATIVE_DOUBLE, &value); H5Aclose(aid); } H5Sclose(space); } else if (api_is_integer(args[2])) { // e.g., hdf.name = 123; int value = api_get_integer(caller, args[2]); hid_t space = H5Screate(H5S_SCALAR); hid_t aid = H5Acreate(id, name, H5T_NATIVE_INT, space, H5P_DEFAULT); if (aid > 0) { status = H5Awrite(aid, H5T_NATIVE_INT, &value); H5Aclose(aid); } H5Sclose(space); } else if (api_is_string(args[2])) { // e.g., hdf.name = "my property"; const char *ptr = api_get_string(caller, args[2]); hid_t space = H5Screate(H5S_SCALAR); hid_t type = H5Tcopy(H5T_C_S1); H5Tset_size(type, strlen(ptr)); hid_t aid = H5Acreate(id, name, type, space, H5P_DEFAULT); if (aid > 0) { status = H5Awrite(aid, type, ptr); H5Aclose(aid); } H5Sclose(space); H5Tclose(type); } else if (api_is_array(args[2])) { // e.g., hdf.name = [1, 2.0, 3.3]; hsize_t dims[1] = { api_get_array_size(caller, args[2]) }; if (dims[0] == 0 || dims[0] > 256) api_runtime_error(caller, "unexpected number of attributes"); zsBuffer br(dims[0]*sizeof(double)), bi(dims[0]*sizeof(int)); bool real_flag = false; for (int i = 0; i < dims[0]; i++) { void *o = api_get_array_object2(caller, args[2], i); if (api_is_real(o)) { br.u.pdouble[i] = api_get_real(caller, o); real_flag = true; } else { bi.u.pint[i] = api_get_integer(caller, o); br.u.pdouble[i] = bi.u.pint[i]; } } if (real_flag) { hid_t space = H5Screate_simple(1, dims, NULL); hid_t aid = H5Acreate(id, name, H5T_NATIVE_DOUBLE, space, 0); if (aid > 0) { status = H5Awrite(aid, H5T_NATIVE_DOUBLE, br.u.pdouble); H5Aclose(aid); } H5Sclose(space); } else { hid_t space = H5Screate_simple(1, dims, NULL); hid_t aid = H5Acreate(id, name, H5T_NATIVE_INT, space, 0); if (aid > 0) { status = H5Awrite(aid, H5T_NATIVE_INT, bi.u.pint); H5Aclose(aid); } H5Sclose(space); } } if (status < 0) api_runtime_error(caller, "failed to write attribute"); return 0; } void hdf_check_index(void *caller, int nargs, void** args, zsHDF *o, hsize_t mcount[], hsize_t dstart[], hsize_t dcount[]) { if (nargs-1 > o->ndim) api_runtime_error(caller, "too many dimension specifiers"); for (size_t k = 0; k < o->ndim; k++) { dstart[k] = 0; dcount[k] = o->dims[k]; mcount[0] *= o->dims[k]; } for (int i = 1; i < nargs; i++) { int k = i - 1; if (!api_is_null(args[i])) { mcount[0] /= o->dims[k]; if (api_is_integer(args[i])) { dstart[k] = api_get_integer(caller, args[i]); dcount[k] = 1; } else { dstart[k] = api_get_integer(caller, api_get_array_object(caller, args[i], "0")); dcount[k] = api_get_integer(caller, api_get_array_object(caller, args[i], "1")); if (dcount[k] < dstart[k]) api_runtime_error(caller, "invalid range specifiers"); dcount[k] = dcount[k] - dstart[k] + 1; mcount[0] *= dcount[k]; } } } } void* hdf_get(void *caller, int nargs, void** args) { if (nargs < 2) input_error(caller); if (api_is_string(args[1])) { // hdf.name return hdf_getatt(caller, nargs, args); } // hdf[...] hsize_t mstart[1] = { 0 }, mcount[1] = { 1 }, dstart[H5S_MAX_RANK], dcount[H5S_MAX_RANK]; zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); check_dataset(caller, o); hdf_check_index(caller, nargs, args, o, mcount, dstart, dcount); o->checksize(mcount[0]*o->tsize); hid_t dspace = H5Dget_space(o->did); hid_t mspace = H5Screate_simple(1, mcount, NULL); if (H5Sselect_hyperslab(dspace, H5S_SELECT_SET, dstart, NULL, dcount, NULL) < 0 || H5Sselect_hyperslab(mspace, H5S_SELECT_SET, mstart, NULL, mcount, NULL) < 0 || H5Dread(o->did, o->tid, mspace, dspace, H5P_DEFAULT, o->ptr) < 0) { api_runtime_error(caller, "failed to read data"); } H5Sclose(mspace); H5Sclose(dspace); if (mcount[0] == 1) { switch (o->type) { case HDF_CHAR: return api_create_integer(caller, ((char*)o->ptr)[0]); case HDF_UCHAR: return api_create_integer(caller, ((unsigned char*)o->ptr)[0]); case HDF_SHORT: return api_create_integer(caller, ((short*)o->ptr)[0]); case HDF_USHORT: return api_create_integer(caller, ((unsigned short*)o->ptr)[0]); case HDF_INT: return api_create_integer(caller, ((int*)o->ptr)[0]); case HDF_UINT: return api_create_integer(caller, ((unsigned int*)o->ptr)[0]); case HDF_FLOAT: return api_create_real(caller, ((float*)o->ptr)[0]); case HDF_DOUBLE: return api_create_integer(caller, ((double*)o->ptr)[0]); default: type_error(caller); } } return api_create_user(caller, o->ptr, 0, 0, 0); } static zsRegPrimitive hdf6("__get", HDF_TYPE, hdf_get); void* hdf_set(void *caller, int nargs, void** args) { if (nargs < 3) input_error(caller); if (api_is_string(args[1])) { // hdf.name = attribute return hdf_putatt(caller, nargs, args); } // hdf[...] hsize_t mstart[1] = { 0 }, mcount[1] = { 1 }, dstart[H5S_MAX_RANK], dcount[H5S_MAX_RANK]; zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); check_dataset(caller, o); hdf_check_index(caller, nargs-1, args, o, mcount, dstart, dcount); hid_t status = -1; hid_t dspace = H5Dget_space(o->did); hid_t mspace = H5Screate_simple(1, mcount, NULL); if (H5Sselect_hyperslab(dspace, H5S_SELECT_SET, dstart, NULL, dcount, NULL) >= 0 && H5Sselect_hyperslab(mspace, H5S_SELECT_SET, mstart, NULL, mcount, NULL) >= 0) { if (api_is_user(args[nargs-1])) { void *ptr = api_get_ptr(caller, args[nargs-1]); status = H5Dwrite(o->did, o->tid, mspace, dspace, H5P_DEFAULT, ptr); } else { zsBuffer buf(mcount[0]*o->tsize); real_t value = api_get_number(caller, args[nargs-1]); hsize_t k; switch (o->type) { case HDF_CHAR: for (k = 0; k < mcount[0]; k++) buf.u.pchar[k] = char(value); break; case HDF_UCHAR: for (k = 0; k < mcount[0]; k++) buf.u.puchar[k] = unsigned char(value); break; case HDF_SHORT: for (k = 0; k < mcount[0]; k++) buf.u.pshort[k] = short(value); break; case HDF_USHORT: for (k = 0; k < mcount[0]; k++) buf.u.pushort[k] = unsigned short(value); break; case HDF_INT: for (k = 0; k < mcount[0]; k++) buf.u.pint[k] = int(value); break; case HDF_UINT: for (k = 0; k < mcount[0]; k++) buf.u.puint[k] = unsigned int(value); break; case HDF_FLOAT: for (k = 0; k < mcount[0]; k++) buf.u.pfloat[k] = float(value); break; case HDF_DOUBLE: for (k = 0; k < mcount[0]; k++) buf.u.pdouble[k] = double(value); break; default: type_error(caller); } status = H5Dwrite(o->did, o->tid, mspace, dspace, H5P_DEFAULT, buf.u.ptr); } } H5Sclose(mspace); H5Sclose(dspace); if (status < 0) api_runtime_error(caller, "failed to write to dataset"); return 0; } static zsRegPrimitive hdf7("__set", HDF_TYPE, hdf_set); void* hdf_cmm(void *caller, int nargs, void** args) { if (nargs < 1) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); hid_t id = o->did; if (!o->flag) id = o->gid; if (nargs == 1) { zsBuffer buf(BUFF_SIZE); if (H5Gget_comment(id, ".", BUFF_SIZE-1, buf.u.pchar) < 0) api_runtime_error(caller, "failed to read comment"); return api_create_string(caller, buf.u.pchar); } if (H5Gset_comment(id, ".", api_get_string(caller, args[1])) < 0) api_runtime_error(caller, "failed to write comment"); return 0; } static zsRegPrimitive hdf8("cmm", HDF_TYPE, hdf_cmm); void* hdf_list(void *caller, int nargs, void** args) { if (nargs < 1) input_error(caller); zsHDF *o = (zsHDF*)api_get_user(caller, args[0], HDF_TYPE); hsize_t k, n; zsBuffer buf(BUFF_SIZE); printf("------ group ------\n"); H5Gget_num_objs(o->gid, &n); for (k = 0; k < n; k++) { hid_t type = H5Gget_objtype_by_idx(o->gid, k); switch(type) { case H5G_LINK: printf("link"); break; case H5G_GROUP: printf("group"); break; case H5G_DATASET: printf("dataset"); break; case H5G_TYPE: printf("type"); break; default: printf("?"); } H5Gget_objname_by_idx(o->gid, k, buf.u.pchar, BUFF_SIZE-1); buf.u.pchar[BUFF_SIZE-1] = 0; printf(": %s\n", buf); H5Tclose(type); } n = H5Aget_num_attrs(o->gid); printf("attibute:"); for (k = 0; k < n; k++) { hid_t aid = H5Aopen_idx(o->gid, (unsigned int)k); H5Aget_name(aid, BUFF_SIZE-1, buf.u.pchar); buf.u.pchar[BUFF_SIZE-1] = 0; H5Aclose(aid); printf(" %s", buf.u.pchar); } printf("\n"); if (!o->flag) return 0; printf("------ dataset ------\ntype: "); switch (o->type) { case HDF_CHAR: printf("H5T_NATIVE_CHAR\n"); break; case HDF_UCHAR: printf("H5T_NATIVE_UCHAR\n"); break; case HDF_SHORT: printf("H5T_NATIVE_SHORT\n"); break; case HDF_USHORT: printf("H5T_NATIVE_USHORT\n"); break; case HDF_INT: printf("H5T_NATIVE_INT\n"); break; case HDF_UINT: printf("H5T_NATIVE_UINT\n"); break; case HDF_FLOAT: printf("H5T_NATIVE_FLOAT\n"); break; case HDF_DOUBLE: printf("H5T_NATIVE_DOUBLE\n"); break; default: printf("?\n"); } printf("dimensions:"); for (k = 0; k < o->ndim; k++) printf(" %d", o->dims[k]); printf("\n"); n = H5Aget_num_attrs(o->did); printf("attibute:"); for (k = 0; k < n; k++) { hid_t aid = H5Aopen_idx(o->did, (unsigned int)k); H5Aget_name(aid, BUFF_SIZE-1, buf.u.pchar); buf.u.pchar[BUFF_SIZE-1] = 0; H5Aclose(aid); printf(" %s", buf.u.pchar); } printf("\n"); fflush(stdout); return 0; } static zsRegPrimitive hdf9("list", HDF_TYPE, hdf_list);