summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Wendling <wendling@ncsa.uiuc.edu>2001-01-09 20:04:29 (GMT)
committerBill Wendling <wendling@ncsa.uiuc.edu>2001-01-09 20:04:29 (GMT)
commitd2c9b6d8d99a83246d7b278688676820b3abb2a0 (patch)
tree707cd91985266611fa2afe79e7278480bd0f3f9d
parentfbf2fd987f7150d051ca85a11f18d33d30570189 (diff)
downloadhdf5-d2c9b6d8d99a83246d7b278688676820b3abb2a0.zip
hdf5-d2c9b6d8d99a83246d7b278688676820b3abb2a0.tar.gz
hdf5-d2c9b6d8d99a83246d7b278688676820b3abb2a0.tar.bz2
[svn-r3248] Purpose:
New Feature Description: Changed the command line flags in the h5dumper so that they accept both short and long flags. The flag syntax for some have changed (I.e., object ids are no longer -v but -i and -header is now -H or --header, etc.) A new function is added called get_options which can be used for all other tools as well. Platforms tested: Linux
-rw-r--r--tools/h5dump.c775
-rw-r--r--tools/h5tools.c192
-rw-r--r--tools/h5tools.h127
-rwxr-xr-xtools/testh5dump.sh16
4 files changed, 701 insertions, 409 deletions
diff --git a/tools/h5dump.c b/tools/h5dump.c
index f984102..b8440a9 100644
--- a/tools/h5dump.c
+++ b/tools/h5dump.c
@@ -1,38 +1,29 @@
/*-------------------------------------------------------------------------
*
- * Copyright (C) 1998 National Center for Supercomputing Applications.
- * All rights reserved.
+ * Copyright (C) 1998, 1999, 2000, 2001
+ * National Center for Supercomputing Applications
+ * All rights reserved.
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
+#include <stdlib.h>
#include "h5dump.h"
#include "H5private.h"
#include "h5tools.h"
-static int display_oid = 0;
-static int display_data = 1;
-static int d_status = 0;
-static int unamedtype = 0; /* shared data type with no name */
+/* module-scoped global variables */
+static int display_oid;
+static int display_data = 1;
+static int d_status;
+static int unamedtype; /* shared data type with no name */
+static int prefix_len = 1024;
-static int prefix_len = 1024;
-static table_t *group_table = NULL, *dset_table = NULL, *type_table = NULL;
-static char *prefix;
+static table_t *group_table, *dset_table, *type_table;
+static char *prefix;
static const dump_header *dump_header_format;
-/* internal functions */
-static void dump_group(hid_t , const char* );
-static void dump_dataset(hid_t, const char*);
-static void dump_data(hid_t, int);
-static void dump_named_datatype(hid_t , const char *);
-static void dump_oid(hid_t oid);
-static void print_enum(hid_t type);
-
-/* external functions */
-extern void indentation(int);
-extern int print_data(hid_t, hid_t, int);
-
static h5dump_t dataformat = {
0, /*raw*/
@@ -209,6 +200,17 @@ static const dump_header xmlformat = {
")", /*dataspacedimend*/
};
+/* internal functions */
+static void dump_group(hid_t , const char* );
+static void dump_dataset(hid_t, const char*);
+static void dump_data(hid_t, int);
+static void dump_named_datatype(hid_t , const char *);
+static void dump_oid(hid_t oid);
+static void print_enum(hid_t type);
+
+/* external functions */
+extern int print_data(hid_t, hid_t, int);
+
/*-------------------------------------------------------------------------
* Function: usage
*
@@ -220,38 +222,38 @@ static const dump_header xmlformat = {
*
* Modifications:
*
- *-----------------------------------------------------------------------*/
+ *-------------------------------------------------------------------------
+ */
static void
-usage(void)
+usage(const char *progname)
{
- fprintf(stderr, "\n\
-Usage of HDF5 Dumper:\n\
-\n\
-h5dump [-h] [-bb] [-header] [-v] [-V] [-a <names>] [-d <names>] [-g <names>]\n\
- [-l <names>] [-o <fname>] [-t <names>] [-w <number>] <file>\n\
-\n\
- -h Print information on this command and exit.\n\
- -bb Display the conent of the boot block. [Default: don't display]\n\
- -header Display header only; no data is displayed.\n\
- -v Display the object ids\n\
- -V Display version information and exit.\n\
- -a <path> Display the specified attribute(s).\n\
- -d <path> Display the specified dataset(s).\n\
- -g <path> Display the specified group(s) and all the members.\n\
- -l <path> Display the value(s) of the specified soft link(s).\n\
- -t <names> Display the specified named data type(s).\n\
- -w <number> Display the information with the specified maximum number of columns.\n\
- -o <fname> Output the raw data of datasets to a separate file <fname>.\n\
+ fprintf(stderr, "\
+usage: %s [OPTIONS] file\n\
+ OPTIONS\n\
+ -h, --help Print a usage message and exit\n\
+ -B, --bootblock Print the content of the boot block\n\
+ -H, --header Print the header only; no data is displayed\n\
+ -i, --object-ids Print the object ids\n\
+ -V, --version Print version number and exit\n\
+ -a P, --attribute=P Print the specified attribute\n\
+ -d P, --dataset=P Print the specified dataset\n\
+ -g P, --group=P Print the specified group and all members\n\
+ -l P, --soft-link=P Print the value(s) of the specified soft link\n\
+ -o F, --output=F Output raw data into file F\n\
+ -t T, --datatype=T Print the specified named data type\n\
+ -w #, --width=# Set the number of columns of output\n\
\n\
- <number> is an integer greater than 1.\n\
- <path> is the full path from the root group to the object.\n\
+ P - is the full path from the root group to the object.\n\
+ T - is the name of the data type.\n\
+ F - is a filename.\n\
+ # - is an integer greater than 1.\n\
\n\
Example:\n\
\n\
Attribute foo of the group /bar_none in file quux.h5\n\
\n\
h5dump -a /bar_none/foo quux.h5\n\
-\n");
+\n", progname);
}
/*-------------------------------------------------------------------------
@@ -899,7 +901,7 @@ dump_all(hid_t group, const char *name, void UNUSED *op_data)
int i;
H5Gget_objinfo(group, name, FALSE, &statbuf);
- tmp = (char *)malloc(strlen(prefix) + strlen(name) + 2);
+ tmp = malloc(strlen(prefix) + strlen(name) + 2);
strcpy(tmp, prefix);
switch (statbuf.type) {
@@ -942,7 +944,7 @@ dump_all(hid_t group, const char *name, void UNUSED *op_data)
H5Gget_objinfo(obj, ".", TRUE, &statbuf);
if (statbuf.nlink > 1) {
- i = search_obj (dset_table, statbuf.objno);
+ i = search_obj(dset_table, statbuf.objno);
if (i < 0) {
indentation(indent);
@@ -1086,7 +1088,7 @@ dump_group(hid_t gid, const char *name)
H5Gget_objinfo(gid, ".", TRUE, &statbuf);
if (statbuf.nlink > 1) {
- i = search_obj (group_table, statbuf.objno);
+ i = search_obj(group_table, statbuf.objno);
if (i < 0) {
indentation(indent);
@@ -1327,6 +1329,261 @@ set_output_file(const char *fname)
return -1;
}
+static void
+handle_attributes(hid_t fid, const char *attr)
+{
+ dump_selected_attr(fid, attr);
+}
+
+static void
+handle_datasets(hid_t fid, const char *dset)
+{
+ H5G_stat_t statbuf;
+ hid_t dsetid;
+
+ if ((dsetid = H5Dopen(fid, dset)) < 0) {
+ begin_obj(dump_header_format->datasetbegin, dset,
+ dump_header_format->datasetblockbegin);
+ indentation(COL);
+ fprintf(stdout, "h5dump error: unable to open %s\n", dset);
+ end_obj(dump_header_format->datasetend,
+ dump_header_format->datasetblockend);
+ d_status = 1;
+ } else {
+ H5Gget_objinfo(dsetid, ".", TRUE, &statbuf);
+
+ if (statbuf.nlink > 1) {
+ int index = search_obj(dset_table, statbuf.objno);
+
+ if (index >= 0) {
+ if (dset_table->objs[index].displayed) {
+ begin_obj(dump_header_format->datasetbegin, dset,
+ dump_header_format->datasetblockbegin);
+ indentation(indent + COL);
+ printf("%s \"%s\"\n", HARDLINK,
+ dset_table->objs[index].objname);
+ indentation(indent);
+ end_obj(dump_header_format->datasetend,
+ dump_header_format->datasetblockend);
+ } else {
+ strcpy(dset_table->objs[index].objname, dset);
+ dset_table->objs[index].displayed = 1;
+ dump_dataset(dsetid, dset);
+ }
+ } else {
+ d_status = 1;
+ }
+ } else {
+ dump_dataset(dsetid, dset);
+ }
+
+ if (H5Dclose(dsetid) < 1)
+ d_status = 1;
+ }
+}
+
+static void
+handle_groups(hid_t fid, const char *group)
+{
+ H5G_stat_t statbuf;
+ hid_t gid;
+
+ if ((gid = H5Gopen(fid, group)) < 0) {
+ begin_obj(dump_header_format->groupbegin, group,
+ dump_header_format->groupblockbegin);
+ indentation(COL);
+ fprintf(stdout, "h5dump error: unable to open %s\n", group);
+ end_obj(dump_header_format->groupend,
+ dump_header_format->groupblockend);
+ d_status = 1;
+ } else {
+ H5Gget_objinfo(gid, ".", TRUE, &statbuf);
+ strcpy(prefix, group);
+ dump_group(gid, group);
+
+ if (H5Gclose(gid) < 0)
+ d_status = 1;
+ }
+}
+
+static void
+handle_links(hid_t fid, const char *link)
+{
+ H5G_stat_t statbuf;
+
+ if (H5Gget_objinfo(fid, link, FALSE, &statbuf) < 0) {
+ begin_obj(dump_header_format->softlinkbegin, link,
+ dump_header_format->softlinkblockbegin);
+ indentation(COL);
+ fprintf(stdout, "h5dump error: unable to get obj info from %s\n", link);
+ end_obj(dump_header_format->softlinkend,
+ dump_header_format->softlinkblockend);
+ d_status = 1;
+ } else if (statbuf.type == H5G_LINK) {
+ char *buf = malloc(statbuf.linklen*sizeof(char));
+
+ begin_obj(dump_header_format->softlinkbegin, link,
+ dump_header_format->softlinkblockbegin);
+ indentation(COL);
+
+ if (H5Gget_linkval(fid, link, statbuf.linklen, buf) >= 0) {
+ printf("LINKTARGET \"%s\"\n", buf);
+ } else {
+ fprintf(stdout, "h5dump error: unable to get link value\n");
+ d_status = 1;
+ }
+
+ end_obj(dump_header_format->softlinkend,
+ dump_header_format->softlinkblockend);
+ free(buf);
+ } else {
+ begin_obj(dump_header_format->softlinkbegin, link,
+ dump_header_format->softlinkblockbegin);
+ indentation(COL);
+ fprintf(stdout, "h5dump error: %s is not a link\n", link);
+ end_obj(dump_header_format->softlinkend,
+ dump_header_format->softlinkblockend);
+ d_status = 1;
+ }
+}
+
+static void
+handle_datatypes(hid_t fid, const char *type)
+{
+ hid_t typeid;
+
+ if ((typeid = H5Topen(fid, type)) < 0) {
+ /* check if type is unamed data type */
+ int index = 0;
+
+ while (index < type_table->nobjs ) {
+ char name[128], name1[128];
+
+ if (!type_table->objs[index].recorded) {
+ /* unamed data type */
+ sprintf(name, "#%lu:%lu\n",
+ type_table->objs[index].objno[0],
+ type_table->objs[index].objno[1]);
+ sprintf(name1, "/#%lu:%lu\n",
+ type_table->objs[index].objno[0],
+ type_table->objs[index].objno[1]);
+
+ if (!strncmp(name, type, strlen(type)) ||
+ !strncmp(name1, type, strlen(type)))
+ break;
+ }
+
+ index++;
+ }
+
+ if (index == type_table->nobjs) {
+ /* unknown type */
+ begin_obj(dump_header_format->datatypebegin, type,
+ dump_header_format->datatypeblockbegin);
+ indentation(COL);
+ fprintf(stdout, "h5dump error: unable to open %s\n", type);
+ end_obj(dump_header_format->datatypeend,
+ dump_header_format->datatypeblockend);
+ d_status = 1;
+ } else {
+ hid_t dsetid = H5Dopen(fid, type_table->objs[index].objname);
+ typeid = H5Dget_type(dsetid);
+ dump_named_datatype(typeid, type);
+ H5Tclose(typeid);
+ H5Dclose(dsetid);
+ }
+ } else {
+ dump_named_datatype(typeid, type);
+
+ if (H5Tclose(typeid) < 0)
+ d_status = 1;
+ }
+}
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+static const char *s_opts = "hBHvVa:d:g:l:t:w:xD:o:";
+static struct long_options l_opts[] = {
+ { "help", no_arg, 'h' },
+ { "hel", no_arg, 'h' },
+ { "boot-block", no_arg, 'B' },
+ { "boot-bloc", no_arg, 'B' },
+ { "boot-blo", no_arg, 'B' },
+ { "boot-bl", no_arg, 'B' },
+ { "boot-b", no_arg, 'B' },
+ { "boot", no_arg, 'B' },
+ { "boo", no_arg, 'B' },
+ { "bo", no_arg, 'B' },
+ { "header", no_arg, 'H' },
+ { "heade", no_arg, 'H' },
+ { "head", no_arg, 'H' },
+ { "hea", no_arg, 'H' },
+ { "he", no_arg, 'H' },
+ { "object-ids", no_arg, 'i' },
+ { "object-id", no_arg, 'i' },
+ { "object-i", no_arg, 'i' },
+ { "object", no_arg, 'i' },
+ { "objec", no_arg, 'i' },
+ { "obje", no_arg, 'i' },
+ { "obj", no_arg, 'i' },
+ { "ob", no_arg, 'i' },
+ { "version", no_arg, 'V' },
+ { "versio", no_arg, 'V' },
+ { "versi", no_arg, 'V' },
+ { "vers", no_arg, 'V' },
+ { "ver", no_arg, 'V' },
+ { "ve", no_arg, 'V' },
+ { "attribute", require_arg, 'a' },
+ { "attribut", require_arg, 'a' },
+ { "attribu", require_arg, 'a' },
+ { "attrib", require_arg, 'a' },
+ { "attri", require_arg, 'a' },
+ { "attr", require_arg, 'a' },
+ { "att", require_arg, 'a' },
+ { "at", require_arg, 'a' },
+ { "dataset", require_arg, 'd' },
+ { "datase", require_arg, 'd' },
+ { "datas", require_arg, 'd' },
+ { "group", require_arg, 'g' },
+ { "grou", require_arg, 'g' },
+ { "gro", require_arg, 'g' },
+ { "gr", require_arg, 'g' },
+ { "soft-link", require_arg, 'l' },
+ { "soft-lin", require_arg, 'l' },
+ { "soft-li", require_arg, 'l' },
+ { "soft-l", require_arg, 'l' },
+ { "soft", require_arg, 'l' },
+ { "sof", require_arg, 'l' },
+ { "so", require_arg, 'l' },
+ { "datatype", require_arg, 't' },
+ { "datatyp", require_arg, 't' },
+ { "dataty", require_arg, 't' },
+ { "datat", require_arg, 't' },
+ { "width", require_arg, 'w' },
+ { "widt", require_arg, 'w' },
+ { "wid", require_arg, 'w' },
+ { "wi", require_arg, 'w' },
+ { "xml", no_arg, 'x' },
+ { "xm", no_arg, 'x' },
+ { "xml-dtd", require_arg, 'D' },
+ { "xml-dt", require_arg, 'D' },
+ { "xml-d", require_arg, 'D' },
+ { "output", require_arg, 'o' },
+ { "outpu", require_arg, 'o' },
+ { "outp", require_arg, 'o' },
+ { "out", require_arg, 'o' },
+ { "ou", require_arg, 'o' },
+ { NULL, 0, '\0' }
+};
+
+struct handler_t {
+ void (*func)(hid_t, const char *);
+ const char *obj;
+};
+
/*-------------------------------------------------------------------------
* Function: main
*
@@ -1341,23 +1598,24 @@ set_output_file(const char *fname)
* Albert Cheng, 2000/09/30
* Add the -o option--output file for datasets raw data
*
- *-----------------------------------------------------------------------*/
+ *-------------------------------------------------------------------------
+ */
int
-main(int argc, char *argv[])
+main(int argc, const char *argv[])
{
- hid_t fid, gid, dsetid, typeid;
- char *fname = NULL;
- int i, index, curr_arg, display_bb=0, display_all=1, newwidth= 0;
- int nopts=0, *opts;
- char *buf, name[128], name1[128];
- H5G_stat_t statbuf;
- void *edata;
- hid_t (*func)(void*);
- find_objs_t *info = malloc(sizeof(find_objs_t));
+ hid_t fid, gid;
+ const char *progname = "h5dump";
+ char *fname = NULL;
+ int i, display_bb = 0, display_all = 1, newwidth = 0;
+ void *edata;
+ hid_t (*func)(void*);
+ find_objs_t info;
+ int opt;
+ struct handler_t *hand;
if (argc < 2) {
- usage();
- exit(1);
+ usage(progname);
+ exit(EXIT_FAILURE);
}
dump_header_format = &standardformat;
@@ -1369,112 +1627,109 @@ main(int argc, char *argv[])
/* Initialize h5tools lib */
h5tools_init();
- opts = malloc((argc / 2) * sizeof(int));
- opts[0] = -1;
+ /* this will be plenty big enough for holding the info */
+ hand = calloc(argc, sizeof(struct handler_t));
/* parse command line options */
- for (curr_arg = 1; curr_arg < argc; curr_arg++) {
- if (argv[curr_arg][0] == '-') {
- opts[nopts++] = curr_arg;
-
- if (!strcmp(argv[curr_arg],"-h")) {
- usage();
- free(opts);
- exit(0);
- } else if (!strcmp(argv[curr_arg],"-V")) {
- print_version("h5dump");
- free(opts);
- exit(0);
- } else if (!strcmp(argv[curr_arg],"-bb")) {
- display_bb = 1;
- } else if (!strcmp(argv[curr_arg],"-header")) {
- display_data=0;
- } else if (!strcmp(argv[curr_arg],"-v")) {
- display_oid = 1;
- } else if (!strcmp(argv[curr_arg],"-w")) {
- /*
- * this way we know which arg was the -w we know it won't be 0
- * since curr_arg starts at 1
- */
- newwidth = curr_arg;
- } else if (!strcmp(argv[curr_arg], "-o")) {
- /* a separate output file for dataset raw data */
- if (argc == curr_arg){
- /* missing <fname> */
- usage();
- free(opts);
- exit(1);
+ while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
+ switch ((char)opt) {
+ case 'B':
+ display_bb = TRUE;
+ break;
+ case 'H':
+ display_data = FALSE;
+ break;
+ case 'v':
+ display_oid = TRUE;
+ break;
+ case 'V':
+ print_version(progname);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'w':
+ nCols = atoi(opt_arg);
+ break;
+ case 'a':
+ display_all = 0;
+
+ for (i = 0; i < argc; i++)
+ if (!hand[i].func) {
+ hand[i].func = handle_attributes;
+ hand[i].obj = opt_arg;
+ break;
}
- if (set_output_file(argv[curr_arg+1]) < 0){
- /* failed to set output file */
- usage();
- free(opts);
- exit(1);
+ break;
+ case 'd':
+ display_all = 0;
+
+ for (i = 0; i < argc; i++)
+ if (!hand[i].func) {
+ hand[i].func = handle_datasets;
+ hand[i].obj = opt_arg;
+ break;
}
- } else if (!strcmp(argv[curr_arg], "-xml")) {
- dump_header_format = &xmlformat;
- } else if (strcmp(argv[curr_arg],"-a") &&
- strcmp(argv[curr_arg],"-d") &&
- strcmp(argv[curr_arg],"-g") &&
- strcmp(argv[curr_arg],"-l") &&
- strcmp(argv[curr_arg],"-t")) {
- fprintf(stderr, "h5dump error: illegal option %s \n",
- argv[curr_arg]);
- usage();
- free(opts);
- exit(1);
- } else {
- display_all = 0;
- }
- }
- }
- /* check names */
- if (argc == 2) {
- if (opts[0] == 1) {
- /* argv[1] is an option */
- fprintf(stderr, "h5dump error: no <names> or no <file>\n");
- usage();
- free(opts);
- exit(1);
- }
- } else {
- for (i = 0; i < nopts-1; i++) {
- if (opts[i + 1] - opts[i] == 1) {
- if (strcmp(argv[opts[i]], "-bb") &&
- strcmp(argv[opts[i]], "-header") &&
- strcmp(argv[opts[i]], "-xml") &&
- strcmp(argv[opts[i]], "-v")) {
- fprintf(stderr,
- "h5dump error: no <names> after option %s\n",
- argv[opts[i]]);
- usage();
- free(opts);
- exit(1);
+ break;
+ case 'g':
+ display_all = 0;
+
+ for (i = 0; i < argc; i++)
+ if (!hand[i].func) {
+ hand[i].func = handle_groups;
+ hand[i].obj = opt_arg;
+ break;
}
- }
- }
- if (argc - opts[nopts - 1] == 1) {
- fprintf(stderr,"h5dump error: no <file>\n");
- usage();
- free(opts);
- exit(1);
- }
+ break;
+ case 'l':
+ display_all = 0;
+
+ for (i = 0; i < argc; i++)
+ if (!hand[i].func) {
+ hand[i].func = handle_links;
+ hand[i].obj = opt_arg;
+ break;
+ }
- if (argc - opts[nopts - 1] == 2) {
- if (strcmp(argv[opts[i]], "-bb") &&
- strcmp(argv[opts[i]], "-header") &&
- strcmp(argv[opts[i]], "-xml") &&
- strcmp(argv[opts[i]], "-v")) {
- fprintf(stderr,
- "h5dump error: no <file> or no <names> "
- "or no <number> after option %s\n", argv[opts[i]]);
- usage();
- free(opts);
- exit(1);
+ break;
+ case 't':
+ display_all = 0;
+
+ for (i = 0; i < argc; i++)
+ if (!hand[i].func) {
+ hand[i].func = handle_datatypes;
+ hand[i].obj = opt_arg;
+ break;
+ }
+
+ break;
+ case 'o':
+ if (set_output_file(opt_arg) < 0){
+ /* failed to set output file */
+ usage(progname);
+ exit(EXIT_FAILURE);
}
+ break;
+#ifdef 0
+ case 'x':
+ /* select XML output */
+ doxml = TRUE;
+ dump_header_format = &xmlformat;
+ dump_function_table = &xml_function_table;
+ break;
+ case 'D':
+ /* specify alternative XML DTD */
+ xml_dtd_uri = strdup(opt_arg);
+ break;
+#endif /* for future XML stuff */
+ case 'h':
+ usage(progname);
+ exit(EXIT_SUCCESS);
+ case '?':
+ default:
+ usage(progname);
+ exit(EXIT_FAILURE);
}
}
@@ -1486,10 +1741,9 @@ main(int argc, char *argv[])
fid = h5dump_fopen(fname, NULL, 0);
if (fid < 0) {
- fprintf(stderr, "h5dump error: unable to open file %s \n", fname);
- free(opts);
- exit(1);
- }
+ fprintf(stderr, "h5dump error: unable to open file %s\n", fname);
+ exit(EXIT_FAILURE);
+ }
/* allocate and initialize internal data structure */
init_table(&group_table);
@@ -1498,17 +1752,17 @@ main(int argc, char *argv[])
init_prefix(&prefix, prefix_len);
/* init the find_objs_t */
- info->threshold = 0;
- info->prefix_len = 1024;
- info->prefix = malloc(info->prefix_len);
- info->prefix[0] = '\0';
- info->group_table = group_table;
- info->type_table = type_table;
- info->dset_table = dset_table;
- info->status = d_status;
+ info.threshold = 0;
+ info.prefix_len = prefix_len;
+ info.prefix = malloc(info.prefix_len);
+ info.prefix[0] = '\0';
+ info.group_table = group_table;
+ info.type_table = type_table;
+ info.dset_table = dset_table;
+ info.status = d_status;
/* find all shared objects */
- H5Giterate(fid, "/", NULL, find_objs, (void*)info);
+ H5Giterate(fid, "/", NULL, find_objs, (void *)&info);
strcpy(prefix, "");
/* does there exist unamed committed data type */
@@ -1520,7 +1774,7 @@ main(int argc, char *argv[])
dump_tables();
#endif
- if (info->status) {
+ if (info.status) {
printf("internal error! \n");
goto done;
}
@@ -1541,182 +1795,16 @@ main(int argc, char *argv[])
d_status = 1;
} else {
dump_group(gid, "/");
- }
+ }
if (H5Gclose (gid) < 0) {
fprintf(stdout, "h5dump error: unable to close root group\n");
d_status = 1;
}
} else {
- for (i = 0; i < nopts; i++) {
- if (!strcmp(argv[opts[i]],"-a")) {
- for (curr_arg = opts[i] + 1;
- curr_arg < ((i + 1) == nopts ? (argc - 1) : opts[i + 1]);
- curr_arg++)
- dump_selected_attr (fid, argv[curr_arg]);
- } else if (!strcmp(argv[opts[i]],"-d")) {
- for (curr_arg = opts[i] + 1;
- curr_arg < ((i + 1) == nopts ? (argc - 1) : opts[i + 1]);
- curr_arg++) {
-
- if ((dsetid = H5Dopen (fid, argv[curr_arg]))<0) {
- begin_obj(dump_header_format->datasetbegin, argv[curr_arg],
- dump_header_format->datasetblockbegin);
- indentation(COL);
- fprintf(stdout, "h5dump error: unable to open %s\n",
- argv[curr_arg]);
- end_obj(dump_header_format->datasetend,
- dump_header_format->datasetblockend);
- d_status = 1;
- } else {
- H5Gget_objinfo(dsetid, ".", TRUE, &statbuf);
-
- if (statbuf.nlink > 1) {
- index = search_obj (dset_table, statbuf.objno);
-
- if (index >= 0) {
- if (dset_table->objs[index].displayed) {
- begin_obj(dump_header_format->datasetbegin,
- argv[curr_arg],
- dump_header_format->datasetblockbegin);
- indentation(indent + COL);
- printf("%s \"%s\"\n", HARDLINK,
- dset_table->objs[index].objname);
- indentation(indent);
- end_obj(dump_header_format->datasetend,
- dump_header_format->datasetblockend);
- } else {
- strcpy(dset_table->objs[index].objname,
- argv[curr_arg]);
- dset_table->objs[index].displayed = 1;
- dump_dataset(dsetid, argv[curr_arg]);
- }
- } else {
- d_status = 1;
- }
- } else {
- dump_dataset(dsetid, argv[curr_arg]);
- }
-
- if (H5Dclose(dsetid) < 1)
- d_status = 1;
- }
- }
- } else if (!strcmp(argv[opts[i]],"-g")) {
- for (curr_arg = opts[i] + 1;
- curr_arg < ((i + 1) == nopts ? (argc - 1) : opts[i + 1]);
- curr_arg++) {
- if ((gid = H5Gopen(fid, argv[curr_arg])) < 0) {
- begin_obj(dump_header_format->groupbegin, argv[curr_arg],
- dump_header_format->groupblockbegin);
- indentation(COL);
- fprintf(stdout, "h5dump error: unable to open %s\n",
- argv[curr_arg]);
- end_obj(dump_header_format->groupend,
- dump_header_format->groupblockend);
- d_status = 1;
- } else {
- H5Gget_objinfo(gid, ".", TRUE, &statbuf);
- strcpy(prefix, argv[curr_arg]);
- dump_group(gid, argv[curr_arg]);
-
- if (H5Gclose(gid) < 0)
- d_status = 1;
- }
- }
- } else if (!strcmp(argv[opts[i]],"-l")) {
- for (curr_arg = opts[i] + 1;
- curr_arg < ((i + 1) == nopts ? (argc - 1) : opts[i + 1]);
- curr_arg++) {
- if (H5Gget_objinfo(fid, argv[curr_arg], FALSE, &statbuf) < 0) {
- begin_obj(dump_header_format->softlinkbegin,
- argv[curr_arg],
- dump_header_format->softlinkblockbegin);
- indentation(COL);
- fprintf(stdout, "h5dump error: unable to get obj info from %s\n",
- argv[curr_arg]);
- end_obj(dump_header_format->softlinkend,
- dump_header_format->softlinkblockend);
- d_status = 1;
- } else if (statbuf.type == H5G_LINK) {
- buf = malloc(statbuf.linklen*sizeof(char));
- begin_obj(dump_header_format->softlinkbegin,
- argv[curr_arg],
- dump_header_format->softlinkblockbegin);
- indentation(COL);
-
- if (H5Gget_linkval(fid, argv[curr_arg], statbuf.linklen, buf) >= 0) {
- printf("LINKTARGET \"%s\"\n", buf);
- } else {
- fprintf(stdout, "h5dump error: unable to get link value\n");
- d_status = 1;
- }
-
- end_obj(dump_header_format->softlinkend,
- dump_header_format->softlinkblockend);
- free(buf);
- } else {
- begin_obj(dump_header_format->softlinkbegin,
- argv[curr_arg],
- dump_header_format->softlinkblockbegin);
- indentation(COL);
- fprintf(stdout, "h5dump error: %s is not a link\n", argv[curr_arg]);
- end_obj(dump_header_format->softlinkend,
- dump_header_format->softlinkblockend);
- d_status = 1;
- }
- }
- } else if (!strcmp(argv[opts[i]],"-t")) {
- for (curr_arg = opts[i] + 1;
- curr_arg < ((i + 1) == nopts ? (argc - 1) : opts[i + 1]);
- curr_arg++) {
- if ((typeid = H5Topen(fid, argv[curr_arg])) < 0) {
- /* check if argv[curr_arg] is unamed data type */
- index = 0;
-
- while (index < type_table->nobjs ) {
- if (!type_table->objs[index].recorded) { /* unamed data type */
- sprintf(name, "#%lu:%lu\n",
- type_table->objs[index].objno[0],
- type_table->objs[index].objno[1]);
- sprintf(name1, "/#%lu:%lu\n",
- type_table->objs[index].objno[0],
- type_table->objs[index].objno[1]);
-
- if (!strncmp(name, argv[curr_arg], strlen(argv[curr_arg])) ||
- !strncmp(name1, argv[curr_arg], strlen(argv[curr_arg])))
- break;
- }
-
- index++;
- }
-
- if (index == type_table->nobjs) {
- /* unknown type */
- begin_obj(dump_header_format->datatypebegin, argv[curr_arg],
- dump_header_format->datatypeblockbegin);
- indentation(COL);
- fprintf(stdout, "h5dump error: unable to open %s\n",
- argv[curr_arg]);
- end_obj(dump_header_format->datatypeend,
- dump_header_format->datatypeblockend);
- d_status = 1;
- } else {
- dsetid = H5Dopen(fid, type_table->objs[index].objname);
- typeid = H5Dget_type(dsetid);
- dump_named_datatype(typeid, argv[curr_arg]);
- H5Tclose(typeid);
- H5Dclose(dsetid);
- }
- } else {
- dump_named_datatype(typeid, argv[curr_arg]);
-
- if (H5Tclose(typeid) < 0)
- d_status = 1;
- }
- }
- }
- }
+ for (i = 0; i < argc; i++)
+ if (hand[i].func)
+ hand[i].func(fid, hand[i].obj);
}
end_obj(dump_header_format->fileend, dump_header_format->fileblockend);
@@ -1725,17 +1813,16 @@ done:
if (H5Fclose(fid) < 0)
d_status = 1;
+ free(hand);
+
free(group_table->objs);
free(dset_table->objs);
free(type_table->objs);
free(prefix);
- free(info->prefix);
- free(info);
- free(opts);
+ free(info.prefix);
h5tools_close();
H5Eset_auto(func, edata);
-
return d_status;
}
diff --git a/tools/h5tools.c b/tools/h5tools.c
index 4f92a17..1af7a6b 100644
--- a/tools/h5tools.c
+++ b/tools/h5tools.c
@@ -1,6 +1,6 @@
/*
- * Copyright © 1998 NCSA
- * All rights reserved.
+ * Copyright © 1998, 2001 National Center for Supercomputing Applications
+ * All rights reserved.
*
* Programmer: Robb Matzke <matzke@llnl.gov>
* Thursday, July 23, 1998
@@ -8,6 +8,12 @@
* Purpose: A library for displaying the values of a dataset in a human
* readable format.
*/
+
+/*
+ * Portions of this work are derived from _Obfuscated C and Other Mysteries_,
+ * by Don Libes, copyright (c) 1993 by John Wiley & Sons, Inc.
+ */
+
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
@@ -21,15 +27,6 @@
/* taken from h5dumputil.c */
-int indent;
-int compound_data;
-int nCols = 80;
-FILE *rawdatastream; /* should initialize to stdout but gcc moans about it */
-
-static int h5tools_init_g = 0; /* if h5tools lib has been initialized */
-
-int print_data(hid_t oid, hid_t _p_type, int obj_data);
-
/*
* If REPEAT_VERBOSE is defined then character strings will be printed so
* that repeated character sequences like "AAAAAAAAAA" are displayed as
@@ -50,21 +47,35 @@ int print_data(hid_t oid, hid_t _p_type, int obj_data);
* largest value suitable for your machine (for testing use a small value).
*/
#if 1
-#define H5DUMP_BUFSIZE (1024 * 1024)
+#define H5DUMP_BUFSIZE (1024 * 1024)
#else
-#define H5DUMP_BUFSIZE (1024)
+#define H5DUMP_BUFSIZE (1024)
#endif
-#define OPT(X,S) ((X) ? (X) : (S))
-#define ALIGN(A,Z) ((((A) + (Z) - 1) / (Z)) * (Z))
-#define START_OF_DATA 0x0001
-#define END_OF_DATA 0x0002
+#define OPT(X,S) ((X) ? (X) : (S))
+#define ALIGN(A,Z) ((((A) + (Z) - 1) / (Z)) * (Z))
+
+#define START_OF_DATA 0x0001
+#define END_OF_DATA 0x0002
/* Special strings embedded in the output */
-#define OPTIONAL_LINE_BREAK "\001"
+#define OPTIONAL_LINE_BREAK "\001"
/* Variable length string datatype */
-#define STR_INIT_LEN 4096 /*initial length */
+#define STR_INIT_LEN 4096 /*initial length */
+
+/* module-scoped variables */
+static int h5tools_init_g; /* if h5tools lib has been initialized */
+
+int indent;
+int compound_data;
+int nCols = 80;
+FILE *rawdatastream; /* should initialize to stdout but gcc moans about it */
+
+/* ``get_option'' variables */
+int opt_err = 1; /*get_option prints errors if this is on */
+int opt_ind = 1; /*token pointer */
+const char *opt_arg; /*flag argument (or value) */
typedef struct h5dump_str_t {
char *s; /*allocate string */
@@ -94,6 +105,7 @@ typedef struct h5dump_context_t {
typedef herr_t (*H5G_operator_t)(hid_t, const char*, void*);
+extern int print_data(hid_t oid, hid_t _p_type, int obj_data);
extern void init_prefix(char **temp, int length);
extern void init_table(table_t **table);
extern void free_table(table_t **table);
@@ -105,6 +117,148 @@ extern int get_tableflag(table_t*, int);
extern int set_tableflag(table_t*, int);
extern char *get_objectname(table_t*, int);
+
+/*-------------------------------------------------------------------------
+ * Function: get_option
+ *
+ * Purpose: Determine the command-line options a user specified. We can
+ * accept both short and long type command-lines.
+ *
+ * Return: Success: The short valued "name" of the command line
+ * parameter or EOF if there are no more
+ * parameters to process.
+ *
+ * Failure: A question mark.
+ *
+ * Programmer: Bill Wendling
+ * Friday, 5. January 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+get_option(int argc, const char **argv, const char *opts, const struct long_options *l_opts)
+{
+ static int sp = 1; /* character index in current token */
+ int opt_opt; /* option character passed back to user */
+
+ if (sp == 1) {
+ /* check for more flag-like tokens */
+ if (opt_ind >= argc || argv[opt_ind][0] != '-' || argv[opt_ind][1] == '\0') {
+ return EOF;
+ } else if (strcmp(argv[opt_ind], "--") == 0) {
+ opt_ind++;
+ return EOF;
+ }
+ }
+
+ if (sp == 1 && argv[opt_ind][0] == '-' && argv[opt_ind][1] == '-') {
+ /* long command line option */
+ const char *arg = &argv[opt_ind][2];
+ register int i;
+
+ for (i = 0; l_opts && l_opts[i].name; i++) {
+ int len = strlen(l_opts[i].name);
+
+ if (strncmp(arg, l_opts[i].name, len) == 0) {
+ /* we've found a matching long command line flag */
+ opt_opt = l_opts[i].shortval;
+
+ if (l_opts[i].has_arg != no_arg) {
+ if (arg[len] == '=') {
+ opt_arg = &arg[len + 1];
+ } else if (opt_ind < (argc - 1) && argv[opt_ind + 1][0] != '-') {
+ opt_arg = argv[++opt_ind];
+ } else if (l_opts[i].has_arg == require_arg) {
+ if (opt_err)
+ fprintf(stderr,
+ "%s: option required for \"--%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+ } else {
+ if (arg[len] == '=') {
+ if (opt_err)
+ fprintf(stderr,
+ "%s: no option required for \"%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_arg = NULL;
+ }
+
+ break;
+ }
+ }
+
+ if (l_opts[i].name == NULL) {
+ /* exhausted all of the l_opts we have and still didn't match */
+ if (opt_err)
+ fprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_ind++;
+ sp = 1;
+ } else {
+ register char *cp; /* pointer into current token */
+
+ /* short command line option */
+ opt_opt = argv[opt_ind][sp];
+
+ if (opt_opt == ':' || (cp = strchr(opts, opt_opt)) == 0) {
+ if (opt_err)
+ fprintf(stderr, "%s: unknown option \"%c\"\n",
+ argv[0], opt_opt);
+
+ /* if no chars left in this token, move to next token */
+ if (argv[opt_ind][++sp] == '\0') {
+ opt_ind++;
+ sp = 1;
+ }
+
+ return '?';
+ }
+
+ if (*++cp == ':') {
+ /* if a value is expected, get it */
+ if (argv[opt_ind][sp + 1] != '\0') {
+ /* flag value is rest of current token */
+ opt_arg = &argv[opt_ind++][sp + 1];
+ } else if (++opt_ind >= argc) {
+ if (opt_err)
+ fprintf(stderr,
+ "%s: value expected for option \"%c\"\n",
+ argv[0], opt_opt);
+
+ opt_opt = '?';
+ } else {
+ /* flag value is next token */
+ opt_arg = argv[opt_ind++];
+ }
+
+ sp = 1;
+ } else {
+ /* set up to look at next char in token, next time */
+ if (argv[opt_ind][++sp] == '\0') {
+ /* no more in current token, so setup next token */
+ opt_ind++;
+ sp = 1;
+ }
+
+ opt_arg = NULL;
+ }
+ }
+
+ /* return the current flag character found */
+ return opt_opt;
+}
+
/*-------------------------------------------------------------------------
* Function: h5tools_init
*
diff --git a/tools/h5tools.h b/tools/h5tools.h
index e9638a5..f48c7af 100644
--- a/tools/h5tools.h
+++ b/tools/h5tools.h
@@ -1,26 +1,28 @@
/*
- * Copyright © 1998 NCSA
- * All rights reserved.
+ * Copyright © 1998, 1999, 2000, 2001
+ * National Center for Supercomputing Applications
+ * All rights reserved.
*
* Programmer: Robb Matzke <matzke@llnl.gov>
* Thursday, July 23, 1998
*
* Purpose: Support functions for the various tools.
*/
-#ifndef _H5TOOLS_H
-#define _H5TOOLS_H
+#ifndef H5TOOLS_H_
+#define H5TOOLS_H_
#include <hdf5.h>
#include <stdio.h>
+
#if H5_VERS_MAJOR == 1
-#if H5_VERS_MINOR == 2
-#define VERSION12
-#elif H5_VERS_MINOR == 3
-#define VERSION13
-#endif
-#endif
-#define ESCAPE_HTML 1
+# if H5_VERS_MINOR == 2
+# define VERSION12
+# elif H5_VERS_MINOR == 3
+# define VERSION13
+# endif /* H5_VERS_MINOR == 2 */
+#endif /* H5_VERS_MAJOR = 1 */
+#define ESCAPE_HTML 1
/*
* Information about how to format output.
@@ -366,23 +368,75 @@ typedef struct dump_header{
} dump_header;
-hid_t h5dump_fixtype(hid_t f_type);
-int h5dump_dset(FILE *stream, const h5dump_t *info, hid_t dset, hid_t p_typ,
- int indentlevel);
-int h5dump_mem(FILE *stream, const h5dump_t *info, hid_t obj_id, hid_t type,
- hid_t space, void *mem, int indentlevel);
-hid_t h5dump_fopen(const char *fname, char *drivername, size_t drivername_len);
+/*
+ * begin get_option section
+ */
+extern int opt_err; /* getoption prints errors if this is on */
+extern int opt_ind; /* token pointer */
+extern const char *opt_arg; /* flag argument (or value) */
+
+enum {
+ no_arg = 0, /* doesn't take an argument */
+ require_arg, /* requires an argument */
+ optional_arg /* argument is optional */
+};
+
+/*
+ * get_option determines which options are specified on the command line and
+ * returns a pointer to any arguments possibly associated with the option in
+ * the ``opt_arg'' variable. get_option returns the shortname equivalent of
+ * the option. The long options are specified in the following way:
+ *
+ * struct long_options[] = {
+ * { "filename", require_arg, 'f' },
+ * { "append", no_arg, 'a' },
+ * { "width", require_arg, 'w' },
+ * { NULL, 0, 0 }
+ * };
+ *
+ * Long named options can have arguments specified as either:
+ *
+ * ``--param=arg'' or ``--param arg''
+ *
+ * Short named options can have arguments specified as either:
+ *
+ * ``-w80'' or ``-w 80''
+ *
+ * and can have more than one short named option specified at one time:
+ *
+ * -aw80
+ *
+ * in which case those options which expect an argument need to come at the
+ * end.
+ */
+typedef struct long_options {
+ const char *name; /* name of the long option */
+ int has_arg; /* whether we should look for an arg */
+ char shortval; /* the shortname equivalent of long arg
+ * this gets returned from get_option */
+} long_options;
+
+extern int get_option(int argc, const char **argv, const char *opt,
+ const struct long_options *l_opt);
+/*
+ * end get_option section
+ */
+
+extern hid_t h5dump_fixtype(hid_t f_type);
+extern int h5dump_dset(FILE *stream, const h5dump_t *info, hid_t dset,
+ hid_t p_typ, int indentlevel);
+extern int h5dump_mem(FILE *stream, const h5dump_t *info, hid_t obj_id,
+ hid_t type, hid_t space, void *mem, int indentlevel);
+extern hid_t h5dump_fopen(const char *fname, char *drivername, size_t drivername_len);
/*if we get a new program that needs to use the library add its name here*/
typedef enum {
- UNKNOWN,
+ UNKNOWN = 0,
H5LS,
H5DUMP
} ProgType;
-
-
/*struct taken from the dumper. needed in table struct*/
typedef struct obj_t {
unsigned long objno[2];
@@ -392,7 +446,6 @@ typedef struct obj_t {
int objflag;
} obj_t;
-
/*struct for the tables that the find_objs function uses*/
typedef struct table_t {
int size;
@@ -400,8 +453,6 @@ typedef struct table_t {
obj_t *objs;
} table_t;
-
-
/*this struct stores the information that is passed to the find_objs function*/
typedef struct find_objs_t {
int prefix_len;
@@ -413,22 +464,22 @@ typedef struct find_objs_t {
int status;
} find_objs_t;
-herr_t find_objs(hid_t group, const char *name, void *op_data);
-int search_obj (table_t *temp, unsigned long *);
-void init_table(table_t **temp);
-void init_prefix(char **temp, int);
+extern herr_t find_objs(hid_t group, const char *name, void *op_data);
+extern int search_obj (table_t *temp, unsigned long *);
+extern void init_table(table_t **temp);
+extern void init_prefix(char **temp, int);
/* taken from h5dump.h */
-#define ATTRIBUTE_DATA 0
+#define ATTRIBUTE_DATA 0
#define DATASET_DATA 1
-#define ENUM_DATA 2
+#define ENUM_DATA 2
-#define COL 3
-extern int indent;
-extern void indentation(int);
-extern int nCols;
-extern FILE *rawdatastream; /* output stream for raw data */
+#define COL 3
+extern int indent;
+extern void indentation(int);
+extern int nCols;
+extern FILE *rawdatastream; /* output stream for raw data */
/* taken from h5dump.h*/
#define BOOT_BLOCK "BOOT_BLOCK"
@@ -460,8 +511,8 @@ extern FILE *rawdatastream; /* output stream for raw data */
#define END "}"
/* Definitions of useful routines */
-void print_version(const char *program_name);
-void h5tools_init(void);
-void h5tools_close(void);
+extern void print_version(const char *program_name);
+extern void h5tools_init(void);
+extern void h5tools_close(void);
-#endif
+#endif /* H5TOOLS_H_ */
diff --git a/tools/testh5dump.sh b/tools/testh5dump.sh
index 8046a10..f38209e 100755
--- a/tools/testh5dump.sh
+++ b/tools/testh5dump.sh
@@ -73,19 +73,19 @@ TOOLTEST()
# test for displaying groups
TOOLTEST tgroup-1.ddl tgroup.h5
# test for displaying the selected groups
-TOOLTEST tgroup-2.ddl -g /g2 / /y tgroup.h5
+TOOLTEST tgroup-2.ddl -g /g2 -g / -g /y tgroup.h5
# test for displaying simple space datasets
TOOLTEST tdset-1.ddl tdset.h5
# test for displaying selected datasets
-TOOLTEST tdset-2.ddl -header -d dset1 /dset2 dset3 tdset.h5
+TOOLTEST tdset-2.ddl -H -d dset1 -d /dset2 --dataset=dset3 tdset.h5
# test for displaying attributes
TOOLTEST tattr-1.ddl tattr.h5
# test for displaying the selected attributes of string type and scalar space
-TOOLTEST tattr-2.ddl -a attr1 attr4 attr5 tattr.h5
+TOOLTEST tattr-2.ddl -a attr1 --attribute attr4 --attribute=attr5 tattr.h5
# test for header and error messages
-TOOLTEST tattr-3.ddl -header -a attr2 attr tattr.h5
+TOOLTEST tattr-3.ddl --header -a attr2 --attribute=attr tattr.h5
# test for displaying soft links
TOOLTEST tslink-1.ddl tslink.h5
@@ -94,15 +94,15 @@ TOOLTEST tslink-2.ddl -l slink2 tslink.h5
# tests for hard links
TOOLTEST thlink-1.ddl thlink.h5
-TOOLTEST thlink-2.ddl -d /g1/dset2 /dset1 /g1/g1.1/dset3 thlink.h5
-TOOLTEST thlink-3.ddl -d /g1/g1.1/dset3 /g1/dset2 /dset1 thlink.h5
+TOOLTEST thlink-2.ddl -d /g1/dset2 --dataset /dset1 --dataset=/g1/g1.1/dset3 thlink.h5
+TOOLTEST thlink-3.ddl -d /g1/g1.1/dset3 --dataset /g1/dset2 --dataset=/dset1 thlink.h5
TOOLTEST thlink-4.ddl -g /g1 thlink.h5
TOOLTEST thlink-5.ddl -d /dset1 -g /g2 -d /g1/dset2 thlink.h5
# tests for compound data types
TOOLTEST tcomp-1.ddl tcompound.h5
# test for named data types
-TOOLTEST tcomp-2.ddl -t /type1 /type2 /group1/type3 tcompound.h5
+TOOLTEST tcomp-2.ddl -t /type1 --datatype /type2 --datatype=/group1/type3 tcompound.h5
# test for unamed type
TOOLTEST tcomp-3.ddl -t /#5992:0 -g /group2 tcompound.h5
@@ -111,7 +111,7 @@ TOOLTEST tnestcomp-1.ddl tnestedcomp.h5
# test for options
TOOLTEST tall-1.ddl tall.h5
-TOOLTEST tall-2.ddl -header -g /g1/g1.1 -a attr2 tall.h5
+TOOLTEST tall-2.ddl --header -g /g1/g1.1 -a attr2 tall.h5
TOOLTEST tall-3.ddl -d /g2/dset2.1 -l /g1/g1.2/g1.2.1/slink tall.h5
# test for loop detection