summaryrefslogtreecommitdiffstats
path: root/tools/h5ls.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/h5ls.c')
-rw-r--r--tools/h5ls.c425
1 files changed, 363 insertions, 62 deletions
diff --git a/tools/h5ls.c b/tools/h5ls.c
index 918712c..9a386f0 100644
--- a/tools/h5ls.c
+++ b/tools/h5ls.c
@@ -10,7 +10,7 @@
/*
* We include the private header file so we can get to the uniform
* programming environment it declares. Other than that, h5ls only calls
- * HDF5 API functions.
+ * HDF5 API functions (except for H5G_basename())
*/
#include <H5private.h>
#include <h5tools.h>
@@ -21,6 +21,23 @@ static int width_g = 80; /*output width in characters */
static hbool_t dump_g = FALSE; /*display dataset values? */
static hbool_t label_g = FALSE; /*label compound values? */
static hbool_t string_g = FALSE; /*print 1-byte numbers as ASCII? */
+static hbool_t fullname_g = FALSE; /*print full path names */
+static hbool_t recursive_g = FALSE; /*recursive descent listing */
+
+/* Info to pass to the iteration functions */
+typedef struct iter_t {
+ const char *container; /*full name of the container object */
+} iter_t;
+
+/* Table containing object id and object name */
+static struct {
+ int nalloc; /*number of slots allocated */
+ int nobjs; /*number of objects */
+ struct {
+ unsigned long id[2]; /*object number */
+ char *name; /*full object name */
+ } *obj;
+} idtab_g;
/* Information about how to display each type of object */
static struct dispatch_t {
@@ -28,7 +45,7 @@ static struct dispatch_t {
hid_t (*open)(hid_t loc, const char *name);
herr_t (*close)(hid_t obj);
herr_t (*list1)(hid_t obj);
- herr_t (*list2)(hid_t obj);
+ herr_t (*list2)(hid_t obj, const char *name);
} dispatch_g[H5G_NTYPES];
#define DISPATCH(TYPE,NAME,OPEN,CLOSE,LIST1,LIST2) { \
@@ -41,6 +58,7 @@ static struct dispatch_t {
static herr_t list (hid_t group, const char *name, void *cd);
static void display_type(hid_t type, int indent);
+static char *fix_name(const char *path, const char *base);
/*-------------------------------------------------------------------------
@@ -65,7 +83,9 @@ usage: %s [OPTIONS] FILE [OBJECTS...]\n\
OPTIONS\n\
-h, -?, --help Print a usage message and exit\n\
-d, --dump Print the values of datasets\n\
+ -f, --full Print full path names instead of base names\n\
-l, --label Label members of compound datasets\n\
+ -r, --recursive List all groups recursively, avoiding cycles\n\
-s, --string Print 1-byte integer datasets as ASCII\n\
-wN, --width=N Set the number of columns of output\n\
-v, --verbose Generate more verbose output\n\
@@ -83,9 +103,84 @@ usage: %s [OPTIONS] FILE [OBJECTS...]\n\
/*-------------------------------------------------------------------------
+ * Function: sym_insert
+ *
+ * Purpose: Add a symbol to the table.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 21, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+sym_insert(H5G_stat_t *sb, const char *name)
+{
+ int n;
+
+ /*
+ * Don't add it if the link count is 1 because such an object can only
+ * have one name.
+ */
+ if (sb->nlink<2) return;
+
+ /* Extend the table */
+ if (idtab_g.nobjs>=idtab_g.nalloc) {
+ idtab_g.nalloc = MAX(256, 2*idtab_g.nalloc);
+ idtab_g.obj = realloc(idtab_g.obj,
+ idtab_g.nalloc*sizeof(idtab_g.obj[0]));
+ }
+
+ /* Insert the entry */
+ n = idtab_g.nobjs++;
+ idtab_g.obj[n].id[0] = sb->objno[0];
+ idtab_g.obj[n].id[1] = sb->objno[1];
+ idtab_g.obj[n].name = malloc(strlen(name)+1);
+ strcpy(idtab_g.obj[n].name, name);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: sym_lookup
+ *
+ * Purpose: Find another name for the specified object.
+ *
+ * Return: Success: Ptr to another name.
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 21, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static char *
+sym_lookup(H5G_stat_t *sb)
+{
+ int n;
+
+ if (sb->nlink<2) return NULL; /*only one name possible*/
+ for (n=0; n<idtab_g.nobjs; n++) {
+ if (idtab_g.obj[n].id[0]==sb->objno[0] &&
+ idtab_g.obj[n].id[1]==sb->objno[1]) {
+ return idtab_g.obj[n].name;
+ }
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------------------------------
* Function: display_string
*
- * Purpose: Print a string value by escaping unusual characters.
+ * Purpose: Print a string value by escaping unusual characters. If
+ * STREAM is null then we only count how large the output would
+ * be.
*
* Return: Number of characters printed.
*
@@ -97,46 +192,57 @@ usage: %s [OPTIONS] FILE [OBJECTS...]\n\
*-------------------------------------------------------------------------
*/
static int
-display_string(const char *s)
+display_string(FILE *stream, const char *s, hbool_t escape_spaces)
{
int nprint=0;
for (/*void*/; s && *s; s++) {
switch (*s) {
case '"':
- printf("\\\"");
+ if (stream) fprintf(stream, "\\\"");
nprint += 2;
break;
case '\\':
- printf("\\\\");
+ if (stream) fprintf(stream, "\\\\");
nprint += 2;
break;
case '\b':
- printf("\\b");
+ if (stream) fprintf(stream, "\\b");
nprint += 2;
break;
case '\f':
- printf("\\f");
+ if (stream) fprintf(stream, "\\f");
nprint += 2;
break;
case '\n':
- printf("\\n");
+ if (stream) fprintf(stream, "\\n");
nprint += 2;
break;
case '\r':
- printf("\\r");
+ if (stream) fprintf(stream, "\\r");
nprint += 2;
break;
case '\t':
- printf("\\t");
+ if (stream) fprintf(stream, "\\t");
nprint += 2;
break;
+ case ' ':
+ if (escape_spaces) {
+ if (stream) fprintf(stream, "\\ ");
+ nprint += 2;
+ } else {
+ if (stream) fprintf(stream, " ");
+ nprint++;
+ }
+ break;
default:
if (isprint(*s)) {
- putchar(*s);
+ if (stream) putc(*s, stream);
nprint++;
} else {
- printf("\\%03o", *((const unsigned char*)s));
+ if (stream) {
+ fprintf(stream, "\\%03o", *((const unsigned char*)s));
+ }
nprint += 4;
}
break;
@@ -548,7 +654,7 @@ display_cmpd_type(hid_t type, int indent)
/* Name and offset */
name = H5Tget_member_name(type, i);
printf("\n%*s\"", indent+4, "");
- n = display_string(name);
+ n = display_string(stdout, name, FALSE);
printf("\"%*s +%-4lu ", MAX(0, 16-n), "",
(unsigned long)H5Tget_member_offset(type, i));
free(name);
@@ -655,7 +761,7 @@ display_enum_type(hid_t type, int indent)
/* Print members */
for (i=0; i<nmembs; i++) {
printf("\n%*s", indent+4, "");
- nchars = display_string(name[i]);
+ nchars = display_string(stdout, name[i], TRUE);
printf("%*s = ", MAX(0, 16-nchars), "");
if (native<0) {
@@ -685,7 +791,7 @@ display_enum_type(hid_t type, int indent)
/*-------------------------------------------------------------------------
- * Function: display_string
+ * Function: display_string_type
*
* Purpose: Print information about a string data type.
*
@@ -895,7 +1001,7 @@ dump_dataset_values(hid_t dset)
* Print all the values.
*/
printf(" Data:\n");
- if (h5dump(stdout, &info, dset, -1)<0) {
+ if (h5dump_dset(stdout, &info, dset, -1)<0) {
printf(" Unable to print data.\n");
}
@@ -922,24 +1028,65 @@ dump_dataset_values(hid_t dset)
static herr_t
list_attr (hid_t obj, const char *attr_name, void __unused__ *op_data)
{
- hid_t attr;
- int i;
-
- printf(" %-10s %-10s", "Attribute:", attr_name);
- if ((attr = H5Aopen_name (obj, attr_name))) {
- hid_t space = H5Aget_space (attr);
- hsize_t size[64];
- int ndims = H5Sget_simple_extent_dims (space, size, NULL);
- H5Sclose (space);
- printf (" {");
+ hid_t attr, space, type, p_type;
+ hsize_t size[64], nelmts=1;
+ int ndims, i, n;
+ size_t need;
+ void *buf;
+ h5dump_t info;
+
+ printf(" Attribute: ");
+ n = display_string(stdout, attr_name, TRUE);
+ printf("%*s", MAX(0, 10-n), "");
+ if ((attr = H5Aopen_name(obj, attr_name))) {
+ space = H5Aget_space(attr);
+ type = H5Aget_type(attr);
+
+ /* Data space */
+ ndims = H5Sget_simple_extent_dims(space, size, NULL);
+ printf(" {");
for (i=0; i<ndims; i++) {
- HDfprintf (stdout, "%s%Hu", i?", ":"", size[i]);
+ HDfprintf(stdout, "%s%Hu", i?", ":"", size[i]);
+ nelmts *= size[i];
+ }
+ puts("}");
+
+ /* Data type */
+ printf(" Type: ");
+ display_type(type, 15);
+ putchar('\n');
+
+ /* Data */
+ memset(&info, 0, sizeof info);
+ info.idx_fmt = " (%s) ";
+ info.line_ncols = width_g;
+ if (label_g) info.cmpd_name = "%s=";
+ if (string_g && 1==H5Tget_size(type) &&
+ H5T_INTEGER==H5Tget_class(type)) {
+ info.ascii = TRUE;
+ info.elmt_suf1 = "";
+ info.elmt_suf2 = "";
+ info.idx_fmt = " (%s) \"";
+ info.line_suf = "\"";
+ }
+ if ((p_type=h5dump_fixtype(type))>=0) {
+ need = nelmts * MAX(H5Tget_size(type), H5Tget_size(p_type));
+ buf = malloc(need);
+ assert(buf);
+ if (H5Aread(attr, p_type, buf)>=0) {
+ h5dump_mem(stdout, &info, p_type, space, buf);
+ }
+ free(buf);
+ H5Tclose(p_type);
}
- putchar ('}');
- H5Aclose (attr);
+
+ H5Sclose(space);
+ H5Tclose(type);
+ H5Aclose(attr);
+ } else {
+ putchar('\n');
}
- putchar ('\n');
return 0;
}
@@ -1013,7 +1160,7 @@ dataset_list1(hid_t dset)
*-------------------------------------------------------------------------
*/
static herr_t
-dataset_list2(hid_t dset)
+dataset_list2(hid_t dset, const char __unused__ *name)
{
hid_t dcpl; /*dataset creation property list*/
hid_t type; /*data type of dataset */
@@ -1031,6 +1178,7 @@ dataset_list2(hid_t dset)
hsize_t total; /*total size or offset */
hsize_t chsize[64]; /*chunk size in elements */
int ndims; /*dimensionality */
+ int n, max_len; /*max extern file name length */
int i;
if (verbose_g>0) {
@@ -1052,8 +1200,19 @@ dataset_list2(hid_t dset)
/* Print information about external strorage */
if ((nf = H5Pget_external_count(dcpl))>0) {
- printf(" %-10s %d external file%s (num/addr/offset/length)\n",
+ for (i=0, max_len=0; i<nf; i++) {
+ H5Pget_external(dcpl, i, sizeof(f_name), f_name, NULL, NULL);
+ n = display_string(NULL, f_name, TRUE);
+ max_len = MAX(max_len, n);
+ }
+ printf(" %-10s %d external file%s\n",
"Extern:", nf, 1==nf?"":"s");
+ printf(" %4s %10s %10s %10s %s\n",
+ "ID", "DSet-Addr", "File-Addr", "Bytes", "File");
+ printf(" %4s %10s %10s %10s ",
+ "----", "----------", "----------", "----------");
+ for (i=0; i<max_len; i++) putchar('-');
+ putchar('\n');
for (i=0, total=0; i<nf; i++) {
if (H5Pget_external(dcpl, i, sizeof(f_name), f_name, &f_offset,
&f_size)<0) {
@@ -1062,17 +1221,21 @@ dataset_list2(hid_t dset)
i, total, "", "",
i+1<nf?"Following addresses are incorrect":"");
} else if (H5S_UNLIMITED==f_size) {
- HDfprintf(stdout, " #%03d %10Hu %10Hu %10s \"",
+ HDfprintf(stdout, " #%03d %10Hu %10Hu %10s ",
i, total, (hsize_t)f_offset, "INF");
- display_string(f_name);
+ display_string(stdout, f_name, TRUE);
} else {
- HDfprintf(stdout, " #%03d %10Hu %10Hu %10Hu \"",
+ HDfprintf(stdout, " #%03d %10Hu %10Hu %10Hu ",
i, total, (hsize_t)f_offset, f_size);
- display_string(f_name);
+ display_string(stdout, f_name, TRUE);
}
- printf("\"\n");
+ putchar('\n');
total += f_size;
}
+ printf(" %4s %10s %10s %10s ",
+ "----", "----------", "----------", "----------");
+ for (i=0; i<max_len; i++) putchar('-');
+ putchar('\n');
}
/* Print information about raw data filters */
@@ -1111,6 +1274,36 @@ dataset_list2(hid_t dset)
/*-------------------------------------------------------------------------
+ * Function: group_list2
+ *
+ * Purpose: List information about a group which should appear after
+ * information which is general to all objects.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 21, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+group_list2(hid_t grp, const char *name)
+{
+ iter_t iter;
+
+ if (recursive_g) {
+ iter.container = name;
+ H5Giterate(grp, ".", NULL, list, &iter);
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
* Function: datatype_list2
*
* Purpose: List information about a data type which should appear after
@@ -1128,7 +1321,7 @@ dataset_list2(hid_t dset)
*-------------------------------------------------------------------------
*/
static herr_t
-datatype_list2(hid_t type)
+datatype_list2(hid_t type, const char __unused__ *name)
{
printf(" %-10s ", "Type:");
display_type(type, 15);
@@ -1155,7 +1348,7 @@ datatype_list2(hid_t type)
*-------------------------------------------------------------------------
*/
static herr_t
-ragged_list2(hid_t __unused__ ra)
+ragged_list2(hid_t __unused__ ra, const char __unused__ *name)
{
if (dump_g) {
puts(" Data: Not implemented yet (see values of member");
@@ -1215,17 +1408,26 @@ link_open(hid_t location, const char *name)
*-------------------------------------------------------------------------
*/
static herr_t
-list (hid_t group, const char *name, void __unused__ *cd)
+list (hid_t group, const char *name, void *_iter)
{
- hid_t obj;
- char buf[512], comment[50];
+ hid_t obj=-1;
+ char buf[512], comment[50], *fullname=NULL, *s=NULL;
H5G_stat_t sb;
struct tm *tm;
herr_t status;
+ iter_t *iter = (iter_t*)_iter;
+ int n;
- /* Print the object name */
- printf("%-25s ", name);
-
+ /* Print the object name, either full name or base name */
+ fullname = fix_name(iter->container, name);
+ if (fullname_g) {
+ n = display_string(stdout, fullname, TRUE);
+ printf("%*s", MAX(0, 25-n), "");
+ } else {
+ n = display_string(stdout, name, TRUE);
+ printf("%*s", MAX(0, 25-n), "");
+ }
+
/* Get object information */
H5E_BEGIN_TRY {
status = H5Gget_objinfo(group, name, FALSE, &sb);
@@ -1242,13 +1444,29 @@ list (hid_t group, const char *name, void __unused__ *cd)
}
/*
+ * If the object has already been printed then just show the object ID
+ * and return.
+ */
+ if ((s=sym_lookup(&sb))) {
+ printf(", same as ");
+ display_string(stdout, s, TRUE);
+ printf("\n");
+ goto done;
+ } else {
+ sym_insert(&sb, fullname);
+ }
+
+ /*
* Open the object. Not all objects can be opened. If this is the case
* then return right away.
*/
if (sb.type>=0 &&
(NULL==dispatch_g[sb.type].open ||
- (obj=(dispatch_g[sb.type].open)(group, name))<0)) return 0;
-
+ (obj=(dispatch_g[sb.type].open)(group, name))<0)) {
+ printf(" *ERROR*\n");
+ goto done;
+ }
+
/*
* List the first line of information for the object.
*/
@@ -1273,21 +1491,76 @@ list (hid_t group, const char *name, void __unused__ *cd)
comment[0] = '\0';
H5Gget_comment(group, name, sizeof(comment), comment);
strcpy(comment+sizeof(comment)-4, "...");
- if (comment[0]) printf(" %-10s %s\n", "Comment:", comment);
+ if (comment[0]) {
+ printf(" %-10s \"", "Comment:");
+ display_string(stdout, comment, FALSE);
+ puts("\"");
+ }
}
if (sb.type>0 && dispatch_g[sb.type].list2) {
- (dispatch_g[sb.type].list2)(obj);
+ (dispatch_g[sb.type].list2)(obj, fullname);
}
/*
* Close the object.
*/
- if (sb.type>0) (dispatch_g[sb.type].close)(obj);
+ done:
+ if (sb.type>0 && obj>=0) (dispatch_g[sb.type].close)(obj);
+ if (fullname) free(fullname);
return 0;
}
/*-------------------------------------------------------------------------
+ * Function: fix_name
+ *
+ * Purpose: Returns a malloc'd buffer that contains the PATH and BASE
+ * names separated by a single slash. It also removes duplicate
+ * and trailing slashes and insures that the name begins with a
+ * slash.
+ *
+ * Return: Success: Ptr to fixed name from malloc()
+ *
+ * Failure: NULL
+ *
+ * Programmer: Robb Matzke
+ * Thursday, January 21, 1999
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static char *
+fix_name(const char *path, const char *base)
+{
+ size_t n = (path?strlen(path):0) + (base?strlen(base):0) + 3;
+ char *s = malloc(n), prev='\0';
+ int len=0;
+
+ if (path) {
+ /* Slash, followed by path, followed by slash */
+ if ('/'!=*path) prev = s[len++] = '/';
+ for (/*void*/; *path; path++) {
+ if ('/'!=*path || '/'!=prev) prev = s[len++] = *path;
+ }
+ if ('/'!=prev) prev = s[len++] = '/';
+ }
+
+ if (base) {
+ /* Base name w/o trailing slashes */
+ const char *end = base + strlen(base);
+ while (end>base && '/'==end[-1]) --end;
+ for (/*void*/; base<end; base++) {
+ if ('/'!=*base || '/'!=prev) prev = s[len++] = *base;
+ }
+ }
+
+ s[len] = '\0';
+ return s;
+}
+
+
+/*-------------------------------------------------------------------------
* Function: get_width
*
* Purpose: Figure out how wide the screen is. This is highly
@@ -1395,14 +1668,15 @@ main (int argc, char *argv[])
const char *fname = NULL;
const char *progname;
const char *s;
- char *rest;
+ char *rest, *container=NULL;
int argno;
H5G_stat_t sb;
+ iter_t iter;
DISPATCH(H5G_DATASET, "Dataset", H5Dopen, H5Dclose,
dataset_list1, dataset_list2);
DISPATCH(H5G_GROUP, "Group", H5Gopen, H5Gclose,
- NULL, NULL);
+ NULL, group_list2);
DISPATCH(H5G_TYPE, "Type", H5Topen, H5Tclose,
NULL, datatype_list2);
DISPATCH(H5G_LINK, "-> ", link_open, NULL,
@@ -1411,7 +1685,7 @@ main (int argc, char *argv[])
NULL, ragged_list2);
/* Name of this program without the path */
- if ((progname=strrchr (argv[0], '/'))) progname++;
+ if ((progname=strrchr(argv[0], '/'))) progname++;
else progname = argv[0];
/* Default output width */
@@ -1428,8 +1702,13 @@ main (int argc, char *argv[])
exit(0);
} else if (!strcmp(argv[argno], "--dump")) {
dump_g = TRUE;
+ } else if (!strcmp(argv[argno], "--full")) {
+ fullname_g = TRUE;
} else if (!strcmp(argv[argno], "--label")) {
label_g = TRUE;
+ } else if (!strcmp(argv[argno], "--recursive")) {
+ recursive_g = TRUE;
+ fullname_g = TRUE;
} else if (!strcmp(argv[argno], "--string")) {
string_g = TRUE;
} else if (!strncmp(argv[argno], "--width=", 8)) {
@@ -1469,9 +1748,16 @@ main (int argc, char *argv[])
case 'd': /* --dump */
dump_g++;
break;
+ case 'f': /* --full */
+ fullname_g = TRUE;
+ break;
case 'l': /* --label */
label_g = TRUE;
break;
+ case 'r': /* --recursive */
+ recursive_g = TRUE;
+ fullname_g = TRUE;
+ break;
case 's': /* --string */
string_g = TRUE;
break;
@@ -1504,27 +1790,42 @@ main (int argc, char *argv[])
usage(progname);
exit(1);
}
- if (strchr (fname, '%')) {
- plist = H5Pcreate (H5P_FILE_ACCESS);
- H5Pset_family (plist, 0, H5P_DEFAULT);
+ if (strchr(fname, '%')) {
+ plist = H5Pcreate(H5P_FILE_ACCESS);
+ H5Pset_family(plist, 0, H5P_DEFAULT);
}
- if ((file = H5Fopen (fname, H5F_ACC_RDONLY, plist))<0) exit (1);
+ if ((file = H5Fopen(fname, H5F_ACC_RDONLY, plist))<0) exit (1);
/*
* The remaining optional arguments are the names of the objects to list.
* If there are no arguments then list `/'.
*/
if (argno>=argc) {
- H5Giterate(file, "/", NULL, list, NULL);
+ iter.container = "/";
+ H5Giterate(file, "/", NULL, list, &iter);
} else {
for (/*void*/; argno<argc; argno++) {
if (H5Gget_objinfo(file, argv[argno], TRUE, &sb)>=0 &&
+ /*
+ * Specified name is a group. List the complete contents of
+ * the group.
+ */
H5G_GROUP==sb.type) {
- H5Giterate(file, argv[argno], NULL, list, NULL);
+ iter.container = container = fix_name("", argv[argno]);
+ H5Giterate(file, argv[argno], NULL, list, &iter);
+ free(container);
+
} else if ((root=H5Gopen(file, "/"))<0) {
- exit(1);
+ exit(1); /*major problem!*/
+
} else {
- list(root, argv[argno], NULL);
+ /*
+ * Specified name is a non-group object -- list that object.
+ * The container for the object is everything up to the base
+ * name.
+ */
+ iter.container = "/";
+ list(root, argv[argno], &iter);
if (H5Gclose(root)<0) exit(1);
}
}