summaryrefslogtreecommitdiff
path: root/hl/tools/h5watch/h5watch.c
diff options
context:
space:
mode:
Diffstat (limited to 'hl/tools/h5watch/h5watch.c')
-rw-r--r--hl/tools/h5watch/h5watch.c970
1 files changed, 970 insertions, 0 deletions
diff --git a/hl/tools/h5watch/h5watch.c b/hl/tools/h5watch/h5watch.c
new file mode 100644
index 0000000..11514b0
--- /dev/null
+++ b/hl/tools/h5watch/h5watch.c
@@ -0,0 +1,970 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 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/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "h5tools.h"
+#include "h5tools_dump.h"
+#include "H5LDprivate.h"
+
+/*
+ * Note: This tool used private routine
+ */
+#define PROGRAMNAME "h5watch" /* Name of tool */
+#define FIELD_SEP "," /* nested field separator */
+#define DEFAULT_RETRY 50 /* number of times to try opening the file */
+
+
+/*
+ * Note:(see comments in hl/src/H5LDprivate.h)
+ * This tool uses private routines H5LD_construct_vector()and H5LD_clean_vector()
+ * This tool uses H5LD_memb_t data structure declared in H5LDprivate.h
+ */
+
+const char *progname = "h5watch"; /* tool name */
+static char *g_list_of_fields = NULL; /* command line input for "list_of_fields" */
+static char *g_dup_fields = NULL; /* copy of "list_of_fields" */
+static H5LD_memb_t **g_listv = NULL; /* vector info for "list_of_fields" */
+
+static hbool_t g_monitor_size_only = FALSE; /* monitor changes in dataset dimension sizes */
+static unsigned g_polling_interval = 1; /* polling interval to check appended data */
+
+static hbool_t g_label = FALSE; /* label compound values */
+static int g_display_width = 80; /* output width in characters */
+static hbool_t g_simple_output = FALSE; /* make output more machine-readable */
+static unsigned g_retry = DEFAULT_RETRY; /* # of times to try opening the file if somehow file is unstable */
+static hbool_t g_display_hex = FALSE; /* display data in hexadecimal format : LATER */
+static hbool_t g_user_interrupt = FALSE; /* Flag to indicate that user interrupted execution */
+
+static herr_t doprint(hid_t did, hsize_t *start, hsize_t *block, int rank);
+static herr_t slicendump(hid_t did, hsize_t *prev_dims, hsize_t *cur_dims,
+ hsize_t *start, hsize_t *block, int rank, int subrank);
+static herr_t monitor_dataset(hid_t fid, char *dsetname);
+static herr_t process_cmpd_fields(hid_t fid, char *dsetname);
+static herr_t check_dataset(hid_t fid, char *dsetname);
+static void leave(int ret);
+static void usage(const char *prog);
+static void parse_command_line(int argc, const char *argv[]);
+
+
+/*
+ * Command-line options: The user can only specify 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 ="?";
+static struct long_options l_opts[] = {
+ { "help", no_arg, 'h' },
+ { "hel", no_arg, 'h' },
+ { "dim", no_arg, 'd' },
+ { "di", no_arg, 'd' },
+ { "label", no_arg, 'l' },
+ { "labe", no_arg, 'l' },
+ { "lab", no_arg, 'l' },
+ { "la", no_arg, 'l' },
+ { "simple", no_arg, 'S' },
+ { "simpl", no_arg, 'S' },
+ { "simp", no_arg, 'S' },
+ { "sim", no_arg, 'S' },
+ { "si", no_arg, 'S' },
+ { "hexdump", no_arg, 'x' },
+ { "hexdum", no_arg, 'x' },
+ { "hexdu", no_arg, 'x' },
+ { "hexd", no_arg, 'x' },
+ { "hex", no_arg, 'x' },
+ { "width", require_arg, 'w' },
+ { "widt", require_arg, 'w' },
+ { "wid", require_arg, 'w' },
+ { "wi", require_arg, 'w' },
+ { "polling", require_arg, 'p' },
+ { "pollin", require_arg, 'p' },
+ { "polli", require_arg, 'p' },
+ { "poll", require_arg, 'p' },
+ { "pol", require_arg, 'p' },
+ { "po", require_arg, 'p' },
+ { "fields", require_arg, 'f' },
+ { "field", require_arg, 'f' },
+ { "fiel", require_arg, 'f' },
+ { "fie", require_arg, 'f' },
+ { "fi", require_arg, 'f' },
+ { "version", no_arg, 'V' },
+ { "versio", no_arg, 'V' },
+ { "versi", no_arg, 'V' },
+ { "vers", no_arg, 'V' },
+ { "ver", no_arg, 'V' },
+ { "ve", no_arg, 'V' },
+ { NULL, 0, '\0' }
+};
+
+/*-------------------------------------------------------------------------
+ * Function: doprint()
+ *
+ * Purpose: Prepare to print the dataset's appended data.
+ * Call the tools library routine h5tools_dump_dset() to do the printing.
+ * (This routine is mostly copied from dump_dataset_values() in tools/h5ls/h5ls.c
+ * and modified accordingly).
+ *
+ * Return: 0 on success; negative on failure
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+doprint(hid_t did, hsize_t *start, hsize_t *block, int rank)
+{
+ h5tools_context_t ctx; /* print context */
+ h5tool_format_t info; /* Format info for the tools library */
+ static char fmt_double[16], fmt_float[16]; /* Format info */
+ struct subset_t subset; /* Subsetting info */
+ hsize_t ss_start[H5S_MAX_RANK]; /* Info for hyperslab */
+ hsize_t ss_stride[H5S_MAX_RANK]; /* Info for hyperslab */
+ hsize_t ss_block[H5S_MAX_RANK]; /* Info for hyperslab */
+ hsize_t ss_count[H5S_MAX_RANK]; /* Info for hyperslab */
+ int i; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Subsetting information for the tools library printing routines */
+ subset.start.data = ss_start;
+ subset.stride.data = ss_stride;
+ subset.block.data = ss_block;
+ subset.count.data = ss_count;
+
+ /* Initialize subsetting information */
+ for(i = 0; i < rank; i++) {
+ subset.stride.data[i] = 1;
+ subset.count.data[i] = 1;
+ subset.start.data[i] = start[i];
+ subset.block.data[i] = block[i];
+ } /* end for */
+
+ HDmemset(&ctx, 0, sizeof(ctx));
+
+ /* Set to all default values and then override */
+ HDmemset(&info, 0, sizeof info);
+
+ if(g_simple_output) {
+ info.idx_fmt = "";
+ info.line_ncols = 65535; /*something big*/
+ info.line_per_line = 1;
+ info.line_multi_new = 0;
+ info.line_pre = " ";
+ info.line_cont = " ";
+
+ info.arr_pre = "";
+ info.arr_suf = "";
+ info.arr_sep = " ";
+
+ info.cmpd_pre = "";
+ info.cmpd_suf = "";
+ info.cmpd_sep = " ";
+
+ /* The "fields" selected by the user */
+ info.cmpd_listv = (const struct H5LD_memb_t * const *)g_listv;
+
+ if(g_label)
+ info.cmpd_name = "%s=";
+
+ info.elmt_suf1 = " ";
+ info.str_locale = ESCAPE_HTML;
+
+ } else {
+ info.idx_fmt = "(%s)";
+ if(!g_display_width) {
+ info.line_ncols = 65535;
+ info.line_per_line = 1;
+ } /* end if */
+ else
+ info.line_ncols = (unsigned)g_display_width;
+
+ info.line_multi_new = 1;
+
+ /* The "fields" selected by the user */
+ info.cmpd_listv = (const struct H5LD_memb_t * const *)g_listv;
+ if(g_label)
+ info.cmpd_name = "%s=";
+ info.line_pre = " %s ";
+ info.line_cont = " %s ";
+ info.str_repeat = 8;
+ } /* end else */
+
+ /* Floating point types should display full precision */
+ sprintf(fmt_float, "%%1.%dg", FLT_DIG);
+ info.fmt_float = fmt_float;
+ sprintf(fmt_double, "%%1.%dg", DBL_DIG);
+ info.fmt_double = fmt_double;
+
+ info.dset_format = "DSET-%s ";
+ info.dset_hidefileno = 0;
+
+ info.obj_format = "-%lu:"H5_PRINTF_HADDR_FMT;
+ info.obj_hidefileno = 0;
+
+ info.dset_blockformat_pre = "%sBlk%lu: ";
+ info.dset_ptformat_pre = "%sPt%lu: ";
+
+ info.line_indent = "";
+
+ if(g_display_hex) {
+ /* Print all data in hexadecimal format if the `-x' or `--hexdump'
+ * command line switch was given. */
+ info.raw = TRUE;
+ } /* end if */
+
+ /* Print the values. */
+ if((ret_value = h5tools_dump_dset(stdout, &info, &ctx, did, &subset)) < 0)
+ error_msg("unable to print data\n");
+
+ HDfprintf(stdout, "\n");
+
+ return ret_value;
+
+} /* end doprint() */
+
+/*-------------------------------------------------------------------------
+ * Function: slicendump
+ *
+ * Purpose: To dump the slice for each dimension
+ * For example: prev_dims[2] = {5, 4}; cur_dims[2] = {7, 8}
+ * This routine will dump data as follows:
+ * {0, 3} to {0, 7} (1x4 elements)
+ * {1, 3} to {0, 7} (1x4 elements)
+ * {2, 3} to {0, 7} (1x4 elements)
+ * {3, 3} to {0, 7} (1x4 elements)
+ * {4, 3} to {0, 7} (1x4 elements)
+ * {5, 0} to {6, 7} (2x8 elements)
+ *
+ * Return: Non-negative on success
+ * Negative on failure
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+slicendump(hid_t did, hsize_t *prev_dims, hsize_t *cur_dims, hsize_t *start, hsize_t *block, int rank, int subrank)
+{
+ int i; /* Local index variable */
+ int ind; /* Index for the current rank */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ ind = rank - subrank;
+
+ if((subrank - 1) > 0) {
+ /* continue onto the next dimension */
+ for (i = 0; i < (hssize_t)MIN(prev_dims[ind], cur_dims[ind]); i++){
+ start[ind] = (hsize_t)i;
+ if((ret_value = slicendump(did, prev_dims, cur_dims, start, block, rank, subrank-1)) < 0)
+ goto done;
+ } /* end for */
+ } /* end if */
+
+ /* this dimension remains the same or shrinking */
+ if(cur_dims[ind] <= prev_dims[ind])
+ goto done;
+
+ /* select first the slice for the faster changing dimension */
+ /* select later the whole slice for the slower changing dimension */
+ start[ind] = prev_dims[ind];
+ block[ind] = cur_dims[ind] - prev_dims[ind];
+
+ for(i = ind + 1; i < rank; i++){
+ start[i] = 0;
+ block[i] = cur_dims[i];
+ } /* end for */
+
+ /* Print the appended data */
+ ret_value = doprint(did, start, block, rank);
+
+done:
+ return ret_value;
+} /* end slicendump() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: monitor_dataset
+ *
+ * Purpose: To poll a dataset periodically for changes in dimension sizes.
+ * For dataset with unchanged and/or decreased dimension sizes:
+ * it just prints the dimension size changes
+ * For dataset with increase in at least one of its dimension sizes:
+ * it will print the new appended data to the dataset
+ *
+ * Return: Non-negative on success: dataset can be monitored
+ * Negative on failure: dataset cannot be monitored
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+monitor_dataset(hid_t fid, char *dsetname)
+{
+ hid_t did; /* dataset id */
+ hid_t sid; /* dataspace id */
+ int ndims; /* # of dimensions in the dataspace */
+ int i, u; /* local index variable */
+ hsize_t prev_dims[H5S_MAX_RANK]; /* current dataspace dimensions */
+ hsize_t cur_dims[H5S_MAX_RANK]; /* previous dataspace dimensions */
+ herr_t ret_value = SUCCEED; /* return value */
+
+ HDfprintf(stdout, "Monitoring dataset %s...\n", dsetname);
+
+ /* Open the dataset for minitoring */
+ if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
+ error_msg("error in opening dataset \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+ if((sid = H5Dget_space(did)) < 0) {
+ error_msg("error in getting dataspace id for dataset \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Get the dataset's dimension sizes */
+ if((ndims = H5Sget_simple_extent_dims(sid, prev_dims, NULL)) < 0) {
+ error_msg("unable to get dimensions sizes for \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+ HDfflush(stdout);
+
+ /* Loop until an error occurs or the user interrupts execution */
+ while(!g_user_interrupt) {
+
+ /* Refreshes the dataset */
+ if(H5Drefresh(did) < 0) {
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Get the dataset's current dimension sizes */
+ if(H5LDget_dset_dims(did, cur_dims) < 0) {
+ error_msg("unable to get dimension sizes for \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Check the dimension sizes */
+ for(i = 0; i < ndims; i++)
+ if(cur_dims[i] != prev_dims[i])
+ break;
+
+ /* at least one dimension has changed */
+ if(i != ndims) {
+ /* Printing changes in dimension sizes */
+ for(u = 0; u < ndims; u++) {
+ HDfprintf(stdout, "dimension %u: %Hu->%Hu", (unsigned)u, prev_dims[u], cur_dims[u]);
+ if(cur_dims[u] > prev_dims[u])
+ HDfprintf(stdout, " (increases)\n");
+ else if(cur_dims[u] < prev_dims[u])
+ HDfprintf(stdout, " (decreases)\n");
+ else
+ HDfprintf(stdout, " (unchanged)\n");
+ }
+
+ /* Printing elements appended to the dataset if there is */
+ if(!g_monitor_size_only) {
+
+ /* See if at least one dimension size has increased */
+ for(u = 0; u < ndims; u++) {
+ int j;
+ hsize_t start[H5S_MAX_RANK];
+ hsize_t block[H5S_MAX_RANK];
+
+ /* Print the new appended data to the dataset */
+ if(cur_dims[u] > prev_dims[u]) {
+ HDfprintf(stdout, " Data:\n");
+
+ for(j = 0; j < ndims; j++) {
+ start[j] = 0;
+ block[j] = 1;
+ }
+
+ if((ret_value = slicendump(did, prev_dims, cur_dims, start, block, ndims, ndims)) < 0)
+ goto done;
+ break;
+ }
+ } /* end for */
+ }
+ HDfflush(stdout);
+ }
+
+ /* Save the current dimension sizes */
+ HDmemcpy(prev_dims, cur_dims, (size_t)ndims * sizeof(hsize_t));
+
+ /* Sleep before next monitor */
+ HDsleep(g_polling_interval);
+ } /* end while */
+
+ HDfflush(stdout);
+
+done:
+ /* Closing */
+ H5E_BEGIN_TRY
+ H5Dclose(did);
+ H5E_END_TRY
+
+ return(ret_value);
+} /* monitor_dataset() */
+
+/*-------------------------------------------------------------------------
+ * Function: process_cmpd_fields
+ *
+ * Purpose: To check whether the fields selected in "g_list_of_fields"
+ * are valid fields associated with the dataset.
+ *
+ * Return: 0 on success; negative on failure
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+process_cmpd_fields(hid_t fid, char *dsetname)
+{
+ hid_t did=-1; /* dataset id */
+ hid_t dtid=-1, tid=-1; /* dataset's data type id */
+ size_t len; /* number of comma-separated fields in "g_list_of_fields" */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ HDassert(g_list_of_fields && *g_list_of_fields);
+
+ /* Open the dataset */
+ if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
+ error_msg("error in opening dataset \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Get the dataset's datatype */
+ if(((dtid = H5Dget_type(did)) < 0) || (tid = H5Tget_native_type(dtid, H5T_DIR_DEFAULT)) < 0) {
+ error_msg("error in getting dataset's datatype\n");
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Check to make sure that the dataset's datatype is compound type */
+ if(H5Tget_class(dtid) != H5T_COMPOUND) {
+ error_msg("dataset should be compound type for <list_of_fields>\n");
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Make a copy of "g_list_of_fields" */
+ if((g_dup_fields = HDstrdup(g_list_of_fields)) == NULL) {
+ error_msg("error in duplicating g_list_of_fields\n");
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Estimate the number of comma-separated fields in "g_list of_fields" */
+ len = HDstrlen(g_list_of_fields)/2 + 2;
+
+ /* Allocate memory for a list vector of H5LD_memb_t structures to store "g_list_of_fields" info */
+ if((g_listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))) == NULL) {
+ error_msg("error in allocating memory for H5LD_memb_t\n");
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Process and store info for "g_listv" */
+ if(H5LD_construct_vector(g_dup_fields, g_listv, tid) < 0) {
+ error_msg("error in processing <list_of_fields>\n");
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Will free memory for g_listv and g_dup_fields when exiting from h5watch */
+done:
+ /* Closing */
+ H5E_BEGIN_TRY
+ H5Tclose(dtid);
+ H5Tclose(tid);
+ H5Dclose(did);
+ H5E_END_TRY
+ return(ret_value);
+} /* process_cmpd_fields() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: check_dataset
+ *
+ * Purpose: To check whether a dataset can be monitored:
+ * A chunked dataset with unlimited or max. dimension setting
+ *
+ * Return: Non-negative on success: dataset can be monitored
+ * Negative on failure: dataset cannot be monitored
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+check_dataset(hid_t fid, char *dsetname)
+{
+ hid_t did=-1; /* Dataset id */
+ hid_t dcp=-1; /* Dataset creation property */
+ hid_t sid=-1; /* Dataset's dataspace id */
+ int ndims; /* # of dimensions in the dataspace */
+ unsigned u; /* Local index variable */
+ hsize_t cur_dims[H5S_MAX_RANK]; /* size of dataspace dimensions */
+ hsize_t max_dims[H5S_MAX_RANK]; /* maximum size of dataspace dimensions */
+ hbool_t unlim_max_dims = FALSE; /* whether dataset has unlimited or max. dimension setting */
+ void *edata;
+ H5E_auto2_t func;
+ H5D_layout_t layout;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ /* Disable error reporting */
+ H5Eget_auto2(H5E_DEFAULT, &func, &edata);
+ H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
+
+ /* Open the dataset */
+ if((did = H5Dopen2(fid, dsetname, H5P_DEFAULT)) < 0) {
+ error_msg("unable to open dataset \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Get dataset's creation property list */
+ if((dcp = H5Dget_create_plist(did)) < 0) {
+ error_msg("unable to get dataset's creation property list \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Query dataset's layout; the layout should be chunked or virtual */
+ if((layout = H5Pget_layout(dcp)) < 0) {
+ error_msg("unable to get dataset layout \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+ if(layout != H5D_CHUNKED && layout != H5D_VIRTUAL) {
+ error_msg("\"%s\" should be a chunked or virtual dataset\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ HDmemset(cur_dims, 0, sizeof cur_dims);
+ HDmemset(max_dims, 0, sizeof max_dims);
+
+ /* Get dataset's dataspace */
+ if((sid = H5Dget_space(did)) < 0) {
+ error_msg("can't get dataset's dataspace\"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Get dimension size of dataset's dataspace */
+ if((ndims = H5Sget_simple_extent_dims(sid, cur_dims, max_dims)) < 0) {
+ error_msg("can't get dataspace dimensions for dataset \"%s\"\n", dsetname);
+ ret_value = FAIL;
+ goto done;
+ }
+
+ /* Check whether dataset has unlimited dimension or max. dimension setting */
+ for(u = 0; u < (unsigned)ndims; u++)
+ if(max_dims[u] == H5S_UNLIMITED || cur_dims[u] != max_dims[u]) {
+ unlim_max_dims = TRUE;
+ break;
+ }
+
+ if(!unlim_max_dims) {
+ error_msg("\"%s\" should have unlimited or max. dimension setting\n", dsetname);
+ ret_value = FAIL;
+ }
+
+done:
+ H5Eset_auto2(H5E_DEFAULT, func, edata);
+
+ /* Closing */
+ H5E_BEGIN_TRY
+ H5Sclose(sid);
+ H5Pclose(dcp);
+ H5Dclose(did);
+ H5E_END_TRY
+
+ return(ret_value);
+} /* check_dataset() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: leave
+ *
+ * Purpose: Close the H5 Tools library and exit
+ *
+ * Return: Does not return
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+leave(int ret)
+{
+ h5tools_close();
+
+ exit(ret);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Print the usage message about h5watch (only long options)
+ *
+ * Return: void
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage(const char *prog)
+{
+ HDfflush(stdout);
+ HDfprintf(stdout, "Usage: %s [OPTIONS] [OBJECT]\n", prog);
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " OPTIONS\n");
+ HDfprintf(stdout, " --help Print a usage message and exit.\n");
+ HDfprintf(stdout, " --version Print version number and exit.\n");
+ HDfprintf(stdout, " --label Label members of compound typed dataset.\n");
+ HDfprintf(stdout, " --simple Use a machine-readable output format.\n");
+ HDfprintf(stdout, " --dim Monitor changes in size of dataset dimensions only.\n");
+ HDfprintf(stdout, " --width=N Set the number of columns to N for output.\n");
+ HDfprintf(stdout, " A value of 0 sets the number of columns to the\n");
+ HDfprintf(stdout, " maximum (65535). The default width is 80 columns.\n");
+ HDfprintf(stdout, " --polling=N Set the polling interval to N (in seconds) when the\n");
+ HDfprintf(stdout, " dataset will be checked for appended data. The default\n");
+ HDfprintf(stdout, " polling interval is 1.\n");
+ HDfprintf(stdout, " --fields=<list_of_fields>\n");
+ HDfprintf(stdout, " Display data for the fields specified in <list_of_fields>\n");
+ HDfprintf(stdout, " for a compound data type. <list_of_fields> can be\n");
+ HDfprintf(stdout, " specified as follows:\n");
+ HDfprintf(stdout, " 1) A comma-separated list of field names in a\n");
+ HDfprintf(stdout, " compound data type. \",\" is the separator\n");
+ HDfprintf(stdout, " for field names while \".\" is the separator\n");
+ HDfprintf(stdout, " for a nested field.\n");
+ HDfprintf(stdout, " 2) A single field name in a compound data type.\n");
+ HDfprintf(stdout, " Can use this option multiple times.\n");
+ HDfprintf(stdout, " Note that backslash is the escape character to avoid\n");
+ HDfprintf(stdout, " characters in field names that conflict with the tool's\n");
+ HDfprintf(stdout, " separators.\n");
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " OBJECT is specified as [<filename>/<path_to_dataset>/<dsetname>]\n");
+ HDfprintf(stdout, " <filename> Name of the HDF5 file. It may be preceded by path\n");
+ HDfprintf(stdout, " separated by slashes to the specified HDF5 file.\n");
+ HDfprintf(stdout, " <path_to_dataset> Path separated by slashes to the specified dataset\n");
+ HDfprintf(stdout, " <dsetname> Name of the dataset\n");
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " User can end the h5watch process by ctrl-C (SIGINT) or kill the process (SIGTERM).\n");
+
+} /* usage() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: parse_command_line
+ *
+ * Purpose: Parse the command line for h5watch (take only long options)
+ *
+ * Return: Success: Set the corresponding command flags and return void
+ * Failure: Exits program with EXIT_FAILURE value.
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+parse_command_line(int argc, const char *argv[])
+{
+ int opt; /* Command line option */
+ int tmp;
+
+ /* no arguments */
+ if (argc == 1) {
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+
+ /* parse command line options */
+ while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
+ switch ((char)opt) {
+ case '?':
+ case 'h': /* --help */
+ usage(h5tools_getprogname());
+ leave(EXIT_SUCCESS);
+
+ case 'V': /* --version */
+ print_version(progname);
+ leave(EXIT_SUCCESS);
+ break;
+
+ case 'w': /* --width=N */
+ g_display_width = (int)HDstrtol(opt_arg, NULL, 0);
+ if(g_display_width < 0) {
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+ break;
+
+ case 'd': /* --dim */
+ g_monitor_size_only = TRUE;
+ break;
+
+ case 'S': /* --simple */
+ g_simple_output = TRUE;
+ break;
+
+ case 'l': /* --label */
+ g_label = TRUE;
+ break;
+
+ case 'p': /* --polling=N */
+ /* g_polling_interval = HDstrtod(opt_arg, NULL); */
+ if((tmp = (int)HDstrtol(opt_arg, NULL, 10)) <= 0) {
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+ g_polling_interval = (unsigned)tmp;
+ break;
+
+ case 'f': /* --fields=<list_of_fields> */
+ if(g_list_of_fields == NULL) {
+ if((g_list_of_fields = HDstrdup(opt_arg)) == NULL) {
+ error_msg("memory allocation failed (file %s:line %d)\n",
+ __FILE__, __LINE__);
+ leave(EXIT_FAILURE);
+ }
+ } else {
+ char *str;
+
+ if((str = HDstrdup(opt_arg)) == NULL) {
+ error_msg("memory allocation failed (file %s:line %d)\n",
+ __FILE__, __LINE__);
+ leave(EXIT_FAILURE);
+ }
+ if((g_list_of_fields = (char *)HDrealloc(g_list_of_fields, HDstrlen(g_list_of_fields) + HDstrlen(str) + 2)) == NULL) {
+ error_msg("memory allocation failed (file %s:line %d)\n",
+ __FILE__, __LINE__);
+ leave(EXIT_FAILURE);
+
+ }
+ HDstrcat(g_list_of_fields, FIELD_SEP);
+ HDstrcat(g_list_of_fields, str);
+ }
+
+ break;
+
+ default:
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+ }
+
+
+ /* check for object to be processed */
+ if (argc <= opt_ind) {
+ error_msg("missing dataset name\n");
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+} /* parse_command_line() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: catch_signal
+ *
+ * Purpose: The signal handler to catch the signals:
+ * SIGTERM and SIGINT and set flag to get out of the main loop
+ *
+ * Return: No return
+ *
+ * Programmer: Vailin Choi; November 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+static void catch_signal(int H5_ATTR_UNUSED signo)
+{
+ /* Set the flag to get out of the main loop */
+ g_user_interrupt = TRUE;
+} /* catch_signal() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: h5watch
+ *
+ * Return: Success: 0
+ * Failure: 1
+ *
+ * Programmer: Vailin Choi; August 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(int argc, const char *argv[])
+{
+ char drivername[50]; /* VFD name */
+ char *fname = NULL; /* File name */
+ char *dname = NULL; /* Dataset name */
+ void *edata; /* Error reporting */
+ H5E_auto2_t func; /* Error reporting */
+ char *x; /* Temporary string pointer */
+ hid_t fid = -1; /* File ID */
+ hid_t fapl = -1; /* File access property list */
+
+ /* Set up tool name and exit status */
+ h5tools_setprogname(PROGRAMNAME);
+ h5tools_setstatus(EXIT_SUCCESS);
+
+ /* Disable error reporting */
+ H5Eget_auto2(H5E_DEFAULT, &func, &edata);
+ H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
+
+ /* Initialize h5tools lib */
+ h5tools_init();
+
+ /* To exit from h5watch for SIGTERM signal */
+ if(HDsignal(SIGTERM, catch_signal) == SIG_ERR) {
+ error_msg("An error occurred while setting a signal handler.\n");
+ leave(EXIT_FAILURE);
+ }
+
+ /* To exit from h5watch for SIGINT signal */
+ if(HDsignal(SIGINT, catch_signal) == SIG_ERR) {
+ error_msg("An error occurred while setting a signal handler.\n");
+ leave(EXIT_FAILURE);
+ }
+
+ /* parse command line options */
+ parse_command_line(argc, argv);
+
+ if(argc <= opt_ind) {
+ error_msg("missing dataset name\n");
+ usage(h5tools_getprogname());
+ leave(EXIT_FAILURE);
+ }
+
+ /* Mostly copied from tools/h5ls coding & modified accordingly */
+ /*
+ * [OBJECT] is specified as
+ * [<filename>/<path_to_dataset>/<dsetname>]
+ *
+ * Example: ../dir1/foo/bar/dset
+ * \_________/\______/
+ * file obj
+ *
+ * The dichotomy is determined by calling H5Fopen() repeatedly until it
+ * succeeds. The first call uses the entire name and each subsequent call
+ * chops off the last component. If we reach the beginning of the name
+ * then there must have been something wrong with the file (perhaps it
+ * doesn't exist).
+ */
+ if((fname = HDstrdup(argv[opt_ind])) == NULL) {
+ error_msg("memory allocation failed (file %s:line %d)\n",
+ __FILE__, __LINE__);
+ h5tools_setstatus(EXIT_FAILURE);
+ }
+
+ /* Create a copy of file access property list */
+ if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ return -1;
+
+ /* Set to use the latest library format */
+ if(H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0)
+ return -1;
+
+ do {
+ while(fname && *fname) {
+ fid = h5tools_fopen(fname, H5F_ACC_RDONLY|H5F_ACC_SWMR_READ, fapl, NULL, drivername, sizeof drivername);
+
+ if(fid >= 0) {
+ HDfprintf(stdout, "Opened \"%s\" with %s driver.\n", fname, drivername);
+ break; /*success*/
+ } /* end if */
+
+ /* Shorten the file name; lengthen the object name */
+ x = dname;
+ dname = HDstrrchr(fname, '/');
+ if(x)
+ *x = '/';
+ if(!dname)
+ break;
+ *dname = '\0';
+ } /* end while */
+ /* Try opening the file again if somehow unstable */
+ } while(g_retry-- > 0 && fid == FAIL);
+
+ if(fid < 0) {
+ error_msg("unable to open file \"%s\"\n", fname);
+ if(fname) HDfree(fname);
+ if(fapl >= 0) H5Pclose(fapl);
+ leave(EXIT_FAILURE);
+ }
+
+ if(!dname) {
+ error_msg("no dataset specified\n");
+ h5tools_setstatus(EXIT_FAILURE);
+ } else {
+ *dname = '/';
+ x = dname;
+ if((dname = HDstrdup(dname)) == NULL) {
+ error_msg("memory allocation failed (file %s:line %d)\n",
+ __FILE__, __LINE__);
+ h5tools_setstatus(EXIT_FAILURE);
+ } else {
+ *x = '\0';
+ /* Validate dataset */
+ if(check_dataset(fid, dname) < 0)
+ h5tools_setstatus(EXIT_FAILURE);
+ /* Validate input "fields" */
+ else if(g_list_of_fields && *g_list_of_fields)
+ if(process_cmpd_fields(fid, dname) < 0)
+ h5tools_setstatus(EXIT_FAILURE);
+ }
+ }
+
+ /* If everything is fine, start monitoring the datset */
+ if(h5tools_getstatus() != EXIT_FAILURE)
+ if(monitor_dataset(fid, dname) < 0)
+ h5tools_setstatus(EXIT_FAILURE);
+
+ /* Free spaces */
+ if(fname) HDfree(fname);
+ if(dname) HDfree(dname);
+ if(g_list_of_fields) HDfree(g_list_of_fields);
+ if(g_listv) {
+ H5LD_clean_vector(g_listv);
+ HDfree(g_listv);
+ }
+ if(g_dup_fields) HDfree(g_dup_fields);
+
+ /* Close the file access property list */
+ if(fapl >= 0 && H5Pclose(fapl) < 0) {
+ error_msg("unable to close file access property list\n");
+ h5tools_setstatus(EXIT_FAILURE);
+ }
+
+ /* Close the file */
+ if(H5Fclose(fid) < 0) {
+ error_msg("unable to close file\n");
+ h5tools_setstatus(EXIT_FAILURE);
+ }
+
+ H5Eset_auto2(H5E_DEFAULT, func, edata);
+ /* exit */
+ leave(h5tools_getstatus());
+} /* main() */
+