From 8d1b51e1ee38cd53051b4a1f01b4cfcce8cfd348 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Thu, 22 Feb 2001 16:55:15 -0500 Subject: [svn-r3490] Purpose: Code Movement Description: Moved tools code into own separate directories. This is the library code all of them share. Platforms tested: Linux, Kelgia --- tools/lib/Dependencies | 0 tools/lib/Makefile.in | 43 + tools/lib/h5tools.c | 2448 +++++++++++++++++++++++++++++++++++++++++++++++ tools/lib/h5tools.h | 517 ++++++++++ tools/lib/h5tools_str.c | 289 ++++++ tools/lib/h5tools_str.h | 27 + 6 files changed, 3324 insertions(+) create mode 100644 tools/lib/Dependencies create mode 100644 tools/lib/Makefile.in create mode 100644 tools/lib/h5tools.c create mode 100644 tools/lib/h5tools.h create mode 100644 tools/lib/h5tools_str.c create mode 100644 tools/lib/h5tools_str.h diff --git a/tools/lib/Dependencies b/tools/lib/Dependencies new file mode 100644 index 0000000..e69de29 diff --git a/tools/lib/Makefile.in b/tools/lib/Makefile.in new file mode 100644 index 0000000..5e61afd --- /dev/null +++ b/tools/lib/Makefile.in @@ -0,0 +1,43 @@ +## HDF5 Library Makefile(.in) +## +## Copyright (C) 2001 National Center for Supercomputing Applications. +## All rights reserved. +## +## +top_srcdir=@top_srcdir@ +top_builddir=../.. +srcdir=@srcdir@ +SUBDIRS= +@COMMENCE@ + +## Add include directory to the C preprocessor flags, add -lh5tools and +## -lhdf5 to the list of libraries. +## +CPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/tools/lib @CPPFLAGS@ + +## Test programs and scripts. +## +TEST_PROGS= +TEST_SCRIPTS= + +## These are our main targets: library and tools. We link this library +## statically because some systems can only link executables to a single +## shared library and libhdf5 is much bigger than libh5tools. +## +LT_LINK_LIB=$(LT) --mode=link $(CC) -static -rpath $(libdir) +LIB=libh5tools.la + +## Source and object files for the library; do not install +## +LIB_SRC=h5tools.c h5tools_str.c +LIB_OBJ=$(LIB_SRC:.c=.lo) +PUB_LIB= + +PRIVATE_HDR=h5tools.h h5tools_str.h + +## Programs have to be built before they can be tested! +## +check test _test: $(PROGS) + +@CONCLUDE@ diff --git a/tools/lib/h5tools.c b/tools/lib/h5tools.c new file mode 100644 index 0000000..8ac51ef --- /dev/null +++ b/tools/lib/h5tools.c @@ -0,0 +1,2448 @@ +/* + * Copyright (c) 1998-2001 National Center for Supercomputing Applications + * All rights reserved. + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * 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 +#include +#include +#include + +#include "h5tools.h" +#include "h5tools_str.h" +#include "hdf5.h" +#include "H5private.h" + +/* taken from h5dumputil.c */ + +/* + * If REPEAT_VERBOSE is defined then character strings will be printed so + * that repeated character sequences like "AAAAAAAAAA" are displayed as + * + * 'A' repeates 9 times + * + * Otherwise the format is more Perl-like + * + * 'A'*10 + * + */ +#define REPEAT_VERBOSE + +/* + * The output functions need a temporary buffer to hold a piece of the + * dataset while it's being printed. This constant sets the limit on the + * size of that temporary buffer in bytes. For efficiency's sake, choose the + * largest value suitable for your machine (for testing use a small value). + */ +#if 1 +#define H5DUMP_BUFSIZE (1024 * 1024) +#else +#define H5DUMP_BUFSIZE (1024) +#endif + +#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" + +/* 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) */ + +/* Output variables */ +typedef struct h5tools_context_t { + size_t cur_column; /*current column for output */ + size_t cur_elmt; /*current element/output line */ + int need_prefix; /*is line prefix needed? */ + int ndims; /*dimensionality */ + hsize_t p_min_idx[H5S_MAX_RANK]; /*min selected index */ + hsize_t p_max_idx[H5S_MAX_RANK]; /*max selected index */ + int prev_multiline; /*was prev datum multiline? */ + size_t prev_prefix_len;/*length of previous prefix */ + int continuation; /*continuation of previous data?*/ + int size_last_dim; /*the size of the last dimension, + *needed so we can break after each + *row */ + int indent_level; /*the number of times we need some + *extra indentation */ + int default_indent_level; /*this is used when the indent + *level gets changed */ +} h5tools_context_t; + +typedef herr_t (*H5G_operator_t)(hid_t, const char*, void*); + +extern void free_table(table_t **table); +extern void dump_table(char *name, table_t* table); +extern int get_table_idx(table_t *table, unsigned long *); +extern int get_tableflag(table_t*, int); +extern int set_tableflag(table_t*, int); +extern char *get_objectname(table_t*, int); + + +/*------------------------------------------------------------------------- + * Function: error_msg + * + * Purpose: Print a nicely formatted error message to stderr flushing the + * stdout stream first. + * + * Return: Nothing + * + * Programmer: Bill Wendling + * Tuesday, 20. February 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +error_msg(const char *progname, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fflush(stdout); + fprintf(stderr, "%s error: ", progname); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +/*------------------------------------------------------------------------- + * Function: warn_msg + * + * Purpose: Print a nicely formatted warning message to stderr flushing + * the stdout stream first. + * + * Return: Nothing + * + * Programmer: Bill Wendling + * Tuesday, 20. February 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +warn_msg(const char *progname, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fflush(stdout); + fprintf(stderr, "%s warning: ", progname); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +/*------------------------------------------------------------------------- + * 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++) { + size_t 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 + * + * Purpose: Initialize the H5 Tools library. + * This should be called before any other h5tools function is + * called. Effect of any h5tools function called before this + * has been called is undetermined. + * + * Return: None + * + * Programmer: Albert Cheng, 2000-10-31 + * + * Modifications: + *------------------------------------------------------------------------- + */ +void +h5tools_init(void) +{ + if (!h5tools_init_g) { + if (!rawdatastream) + rawdatastream = stdout; + + h5tools_init_g++; + } +} + +/*------------------------------------------------------------------------- + * Function: h5tools_close + * + * Purpose: Close the H5 Tools library by closing or releasing resources + * such as files opened by the library. + * This should be called after all other h5tools functions have + * been called. Effect of any h5tools function called after this + * has been called is undetermined. + * + * Return: None + * + * Programmer: Albert Cheng, 2000-10-31 + * + * Modifications: + *------------------------------------------------------------------------- + */ +void +h5tools_close(void) +{ + if (h5tools_init_g) { + if (rawdatastream && rawdatastream != stdout) { + if (fclose(rawdatastream)) + perror("closing rawdatastream"); + else + rawdatastream = NULL; + } + + h5tools_init_g = 0; + } +} + +/*------------------------------------------------------------------------- + * Function: h5tools_escape + * + * Purpose: Changes all "funny" characters in S into standard C escape + * sequences. If ESCAPE_SPACES is non-zero then spaces are + * escaped by prepending a backslash. + * + * Return: Success: S + * + * Failure: NULL if the buffer would overflow. The + * buffer has as many left-to-right escapes as + * possible before overflow would have happened. + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static char * +h5tools_escape(char *s/*in,out*/, size_t size, int escape_spaces) +{ + register size_t i; + size_t n = strlen(s); + const char *escape; + char octal[8]; + + for (i = 0; i < n; i++) { + switch (s[i]) { + case '"': + escape = "\\\""; + break; + case '\\': + escape = "\\\\"; + break; + case '\b': + escape = "\\b"; + break; + case '\f': + escape = "\\f"; + break; + case '\n': + escape = "\\n"; + break; + case '\r': + escape = "\\r"; + break; + case '\t': + escape = "\\t"; + break; + case ' ': + escape = escape_spaces ? "\\ " : NULL; + break; + default: + if (!isprint((int)*s)) { + sprintf(octal, "\\%03o", (unsigned char)s[i]); + escape = octal; + } else { + escape = NULL; + } + + break; + } + + if (escape) { + size_t esc_size = strlen(escape); + + if (n + esc_size + 1 > size) + /*would overflow*/ + return NULL; + + memmove(s + i + esc_size, s + i, (n - i) + 1); /*make room*/ + memcpy(s + i, escape, esc_size); /*insert*/ + n += esc_size; + i += esc_size - 1; + } + } + + return s; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_is_zero + * + * Purpose: Determines if memory is initialized to all zero bytes. + * + * Return: TRUE if all bytes are zero; FALSE otherwise + * + * Programmer: Robb Matzke + * Monday, June 7, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static hbool_t +h5tools_is_zero(const void *_mem, size_t size) +{ + const unsigned char *mem = (const unsigned char *)_mem; + + while (size-- > 0) + if (mem[size]) + return FALSE; + + return TRUE; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_region + * + * Purpose: Prints information about a dataspace region by appending + * the information to the specified string. + * + * Return: Success: 0 + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, June 7, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +h5dump_region(hid_t region, h5tools_str_t *str/*in,out*/, const h5dump_t *info) +{ + hssize_t nblocks, npoints; + hsize_t alloc_size; + hsize_t *ptdata; + int ndims = H5Sget_simple_extent_ndims(region); + + /* + * These two functions fail if the region does not have blocks or points, + * respectively. They do not currently know how to translate from one to + * the other. + */ + H5E_BEGIN_TRY { + nblocks = H5Sget_select_hyper_nblocks(region); + npoints = H5Sget_select_elem_npoints(region); + } H5E_END_TRY; + + h5tools_str_append(str, "{"); + + /* Print block information */ + if (nblocks > 0) { + int i; + + alloc_size = nblocks * ndims * 2 * sizeof(ptdata[0]); + assert(alloc_size == (hsize_t)((size_t)alloc_size)); /*check for overflow*/ + ptdata = malloc((size_t)alloc_size); + H5_CHECK_OVERFLOW(nblocks, hssize_t, hsize_t); + H5Sget_select_hyper_blocklist(region, (hsize_t)0, (hsize_t)nblocks, ptdata); + + for (i = 0; i < nblocks; i++) { + int j; + + h5tools_str_append(str, info->dset_blockformat_pre, + i ? "," OPTIONAL_LINE_BREAK " " : "", + (unsigned long)i); + + /* Start coordinates and opposite corner */ + for (j = 0; j < ndims; j++) + h5tools_str_append(str, "%s%lu", j ? "," : "(", + (unsigned long)ptdata[i * 2 * ndims + j]); + + for (j = 0; j < ndims; j++) + h5tools_str_append(str, "%s%lu", j ? "," : ")-(", + (unsigned long)ptdata[i * 2 * ndims + j + ndims]); + + h5tools_str_append(str, ")"); + } + + free(ptdata); + } + + /* Print point information */ + if (npoints > 0) { + int i; + + alloc_size = npoints * ndims * sizeof(ptdata[0]); + assert(alloc_size == (hsize_t)((size_t)alloc_size)); /*check for overflow*/ + ptdata = malloc((size_t)alloc_size); + H5_CHECK_OVERFLOW(npoints,hssize_t,hsize_t); + H5Sget_select_elem_pointlist(region, (hsize_t)0, (hsize_t)npoints, ptdata); + + for (i = 0; i < npoints; i++) { + int j; + + h5tools_str_append(str, info->dset_ptformat_pre , + i ? "," OPTIONAL_LINE_BREAK " " : "", + (unsigned long)i); + + for (j = 0; j < ndims; j++) + h5tools_str_append(str, "%s%lu", j ? "," : "(", + (unsigned long)(ptdata[i * ndims + j])); + + h5tools_str_append(str, ")"); + } + + free(ptdata); + } + + h5tools_str_append(str, "}"); + return 0; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_print_char + * + * Purpose: Shove a character into the STR. + * + * Return: Nothing + * + * Programmer: Bill Wendling + * Tuesday, 20. February 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +h5tools_print_char(h5tools_str_t *str, const h5dump_t *info, unsigned char ch) +{ + if (info->str_locale == ESCAPE_HTML) { + if (ch <= ' ' || ch > '~') + h5tools_str_append(str, "%%%02x", ch); + else + h5tools_str_append(str, "%c", (char)ch); + } else { + switch (ch) { + case '"': + h5tools_str_append(str, "\\\""); + break; + case '\\': + h5tools_str_append(str, "\\\\"); + break; + case '\b': + h5tools_str_append(str, "\\b"); + break; + case '\f': + h5tools_str_append(str, "\\f"); + break; + case '\n': + h5tools_str_append(str, "\\n"); + break; + case '\r': + h5tools_str_append(str, "\\r"); + break; + case '\t': + h5tools_str_append(str, "\\t"); + break; + default: + if (isprint(ch)) + h5tools_str_append(str, "%c", (char)ch); + else + h5tools_str_append(str, "\\%03o", ch); + + break; + } + } +} + +/*------------------------------------------------------------------------- + * Function: h5tools_sprint + * + * Purpose: Renders the value pointed to by VP of type TYPE into variable + * length string STR. + * + * Return: A pointer to memory containing the result or NULL on error. + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * Robb Matzke, 1999-04-26 + * Made this function safe from overflow problems by allowing it + * to reallocate the output string. + * + * Robb Matzke, 1999-06-04 + * Added support for object references. The new `container' + * argument is the dataset where the reference came from. + * + * Robb Matzke, 1999-06-07 + * Added support for printing raw data. If info->raw is non-zero + * then data is printed in hexadecimal format. + * + *------------------------------------------------------------------------- + */ +static char * +h5tools_sprint(h5tools_str_t *str/*in,out*/, const h5dump_t *info, + hid_t container, hid_t type, void *vp, h5tools_context_t *ctx) +{ + size_t n, offset, size, nelmts, start; + char *name, quote = '\0'; + unsigned char *ucp_vp = (unsigned char *)vp; + char *cp_vp = (char *)vp; + hid_t memb, obj, region; + int nmembs, otype; + static char fmt_llong[8], fmt_ullong[8]; + H5T_str_t pad; + H5G_stat_t sb; + + /* + * some tempvars to store the value before we append it to the string to + * get rid of the memory alignment problem + */ + double tempdouble; + float tempfloat; + unsigned long_long tempullong; + long_long templlong; + unsigned long tempulong; + long templong; + unsigned int tempuint; + int tempint; + unsigned short tempushort; + short tempshort; + + /* Build default formats for long long types */ + if (!fmt_llong[0]) { + sprintf(fmt_llong, "%%%sd", PRINTF_LL_WIDTH); + sprintf(fmt_ullong, "%%%su", PRINTF_LL_WIDTH); + } + + /* Append value depending on data type */ + start = h5tools_str_len(str); + + if (info->raw) { + size_t i; + + h5tools_str_append(str, "0x"); + n = H5Tget_size(type); + + for (i = 0; i < n; i++) + h5tools_str_append(str, OPT(info->fmt_raw, "%02x"), ucp_vp[i]); + } else if (H5Tequal(type, H5T_NATIVE_FLOAT)) { + memcpy(&tempfloat, vp, sizeof(float)); + h5tools_str_append(str, OPT(info->fmt_float, "%g"), tempfloat); + } else if (H5Tequal(type, H5T_NATIVE_DOUBLE)) { + memcpy(&tempdouble, vp, sizeof(double)); + h5tools_str_append(str, OPT(info->fmt_double, "%g"), tempdouble); + } else if (info->ascii && (H5Tequal(type, H5T_NATIVE_SCHAR) || + H5Tequal(type, H5T_NATIVE_UCHAR))) { + h5tools_print_char(str, info, *ucp_vp); + } else if (H5T_STRING == H5Tget_class(type)) { + unsigned int i; + + quote = '\0'; + size = H5Tget_size(type); + pad = H5Tget_strpad(type); + + for (i = 0; i < size && (cp_vp[i] != '\0' || pad != H5T_STR_NULLTERM); i++) { + int j = 1; + + /* + * Count how many times the next character repeats. If the + * threshold is zero then that means it can repeat any number + * of times. + */ + if (info->str_repeat > 0) + while (i + j < size && cp_vp[i] == cp_vp[i + j]) + j++; + + /* + * Print the opening quote. If the repeat count is high enough to + * warrant printing the number of repeats instead of enumerating + * the characters, then make sure the character to be repeated is + * in it's own quote. + */ + if (info->str_repeat > 0 && j > info->str_repeat) { + if (quote) + h5tools_str_append(str, "%c", quote); + + quote = '\''; + h5tools_str_append(str, "%s%c", i ? " " : "", quote); + } else if (!quote) { + quote = '"'; + h5tools_str_append(str, "%s%c", i ? " " : "", quote); + } + + /* Print the character */ + h5tools_print_char(str, info, ucp_vp[i]); + + /* Print the repeat count */ + if (info->str_repeat && j > info->str_repeat) { +#ifdef REPEAT_VERBOSE + h5tools_str_append(str, "%c repeats %d times", quote, j - 1); +#else + h5tools_str_append(str, "%c*%d", quote, j - 1); +#endif + quote = '\0'; + i += j - 1; + } + + } + + if (quote) + h5tools_str_append(str, "%c", quote); + + if (i == 0) + /*empty string*/ + h5tools_str_append(str, "\"\""); + } else if (H5Tequal(type, H5T_NATIVE_INT)) { + memcpy(&tempint, vp, sizeof(int)); + h5tools_str_append(str, OPT(info->fmt_int, "%d"), tempint); + } else if (H5Tequal(type, H5T_NATIVE_UINT)) { + memcpy(&tempuint, vp, sizeof(unsigned int)); + h5tools_str_append(str, OPT(info->fmt_uint, "%u"), tempuint); + } else if (H5Tequal(type, H5T_NATIVE_SCHAR)) { + h5tools_str_append(str, OPT(info->fmt_schar, "%d"), *cp_vp); + } else if (H5Tequal(type, H5T_NATIVE_UCHAR)) { + h5tools_str_append(str, OPT(info->fmt_uchar, "%u"), *ucp_vp); + } else if (H5Tequal(type, H5T_NATIVE_SHORT)) { + memcpy(&tempshort, vp, sizeof(short)); + h5tools_str_append(str, OPT(info->fmt_short, "%d"), tempshort); + } else if (H5Tequal(type, H5T_NATIVE_USHORT)) { + memcpy(&tempushort, vp, sizeof(unsigned short)); + h5tools_str_append(str, OPT(info->fmt_ushort, "%u"), tempushort); + } else if (H5Tequal(type, H5T_NATIVE_LONG)) { + memcpy(&templong, vp, sizeof(long)); + h5tools_str_append(str, OPT(info->fmt_long, "%ld"), templong); + } else if (H5Tequal(type, H5T_NATIVE_ULONG)) { + memcpy(&tempulong, vp, sizeof(unsigned long)); + h5tools_str_append(str, OPT(info->fmt_ulong, "%lu"), tempulong); + } else if (H5Tequal(type, H5T_NATIVE_LLONG)) { + memcpy(&templlong, vp, sizeof(long_long)); + h5tools_str_append(str, OPT(info->fmt_llong, fmt_llong), templlong); + } else if (H5Tequal(type, H5T_NATIVE_ULLONG)) { + memcpy(&tempullong, vp, sizeof(unsigned long_long)); + h5tools_str_append(str, OPT(info->fmt_ullong, fmt_ullong), tempullong); + } else if (H5Tequal(type, H5T_NATIVE_HSSIZE)) { + if (sizeof(hssize_t) == sizeof(int)) { + memcpy(&tempint, vp, sizeof(int)); + h5tools_str_append(str, OPT(info->fmt_int, "%d"), tempint); + } else if (sizeof(hssize_t) == sizeof(long)) { + memcpy(&templong, vp, sizeof(long)); + h5tools_str_append(str, OPT(info->fmt_long, "%ld"), templong); + } else { + memcpy(&templlong, vp, sizeof(long_long)); + h5tools_str_append(str, OPT(info->fmt_llong, fmt_llong), templlong); + } + } else if (H5Tequal(type, H5T_NATIVE_HSIZE)) { + if (sizeof(hsize_t) == sizeof(int)) { + memcpy(&tempuint, vp, sizeof(unsigned int)); + h5tools_str_append(str, OPT(info->fmt_uint, "%u"), tempuint); + } else if (sizeof(hsize_t) == sizeof(long)) { + memcpy(&tempulong, vp, sizeof(long)); + h5tools_str_append(str, OPT(info->fmt_ulong, "%lu"), tempulong); + } else { + memcpy(&tempullong, vp, sizeof(unsigned long_long)); + h5tools_str_append(str, OPT(info->fmt_ullong, fmt_ullong), tempullong); + } + } else if (H5Tget_class(type) == H5T_COMPOUND) { + int j; + + nmembs = H5Tget_nmembers(type); + h5tools_str_append(str, "%s", OPT(info->cmpd_pre, "{")); + + for (j = 0; j < nmembs; j++) { + if (j) + h5tools_str_append(str, "%s", OPT(info->cmpd_sep, ", " OPTIONAL_LINE_BREAK)); + + /* RPM 2000-10-31 + * If the previous character is a line-feed (which is true when + * h5dump is running) then insert some white space for + * indentation. Be warned that column number calculations will be + * incorrect and that object indices at the beginning of the line + * will be missing (h5dump doesn't display them anyway). */ + if (ctx->indent_level >= 0 && str->len && str->s[str->len - 1] == '\n') { + int x; + + h5tools_str_append(str, OPT(info->line_pre, ""), ""); + + for (x = 0; x < ctx->indent_level + 1; x++) + h5tools_str_append(str, "%s", OPT(info->line_indent, "")); + } + + /* The name */ + name = H5Tget_member_name(type, j); + h5tools_str_append(str, OPT(info->cmpd_name, ""), name); + free(name); + + /* The value */ + offset = H5Tget_member_offset(type, j); + memb = H5Tget_member_type(type, j); + + ctx->indent_level++; + h5tools_sprint(str, info, container, memb, cp_vp + offset , ctx); + ctx->indent_level--; + + H5Tclose(memb); + } + + /* RPM 2000-10-31 + * If the previous character is a line feed (which is true when + * h5dump is running) then insert some white space for indentation. + * Be warned that column number calculations will be incorrect and + * that object indices at the beginning of the line will be missing + * (h5dump doesn't display them anyway). */ + h5tools_str_append(str, "%s", OPT(info->cmpd_end, "")); + + if (ctx->indent_level >= 0 && str->len && str->s[str->len - 1] == '\n') { + int x; + + h5tools_str_append(str, OPT(info->line_pre, ""), ""); + + for (x = 0; x < ctx->indent_level; x++) + h5tools_str_append(str, "%s", OPT(info->line_indent, "")); + } + + h5tools_str_append(str, "%s", OPT(info->cmpd_suf, "}")); + } else if (H5Tget_class(type) == H5T_ENUM) { + char enum_name[1024]; + + if (H5Tenum_nameof(type, vp, enum_name, sizeof enum_name) >= 0) { + h5tools_str_append(str, h5tools_escape(enum_name, sizeof(enum_name), TRUE)); + } else { + size_t i; + + h5tools_str_append(str, "0x"); + n = H5Tget_size(type); + + for (i = 0; i < n; i++) + h5tools_str_append(str, "%02x", ucp_vp[i]); + } + } else if (H5Tequal(type, H5T_STD_REF_DSETREG)) { + /* + * Dataset region reference -- show the type and OID of the referenced + * object, but we are unable to show the region yet because there + * isn't enough support in the data space layer. - rpm 19990604 + */ + if (h5tools_is_zero(vp, H5Tget_size(type))) { + h5tools_str_append(str, "NULL"); + } else { + obj = H5Rdereference(container, H5R_DATASET_REGION, vp); + region = H5Rget_region(container, H5R_DATASET_REGION, vp); + H5Gget_objinfo(obj, ".", FALSE, &sb); + + if (info->dset_hidefileno) + h5tools_str_append(str, info->dset_format, sb.objno[1], sb.objno[0]); + else + h5tools_str_append(str, info->dset_format, + sb.fileno[1], sb.fileno[0], sb.objno[1], sb.objno[0]); + + h5dump_region(region, str, info); + H5Sclose(region); + H5Dclose(obj); + } + } else if (H5Tequal(type, H5T_STD_REF_OBJ)) { + /* + * Object references -- show the type and OID of the referenced + * object. + */ + if (h5tools_is_zero(vp, H5Tget_size(type))) { + h5tools_str_append(str, "NULL"); + } else { + otype = H5Rget_object_type(container, vp); + obj = H5Rdereference(container, H5R_OBJECT, vp); + H5Gget_objinfo(obj, ".", FALSE, &sb); + + /* Print object type and close object */ + switch (otype) { + case H5G_GROUP: + h5tools_str_append(str, GROUPNAME); + H5Gclose(obj); + break; + case H5G_DATASET: + h5tools_str_append(str, DATASET); + H5Dclose(obj); + break; + case H5G_TYPE: + h5tools_str_append(str, DATATYPE); + H5Tclose(obj); + break; + default: + h5tools_str_append(str, "%u-", otype); + break; + } + + /* Print OID */ + if (info->obj_hidefileno) { + h5tools_str_append(str, info->obj_format, sb.objno[1], sb.objno[0]); + } else { + h5tools_str_append(str, info->obj_format, + sb.fileno[1], sb.fileno[0], sb.objno[1], sb.objno[0]); + } + } + } else if (H5Tget_class(type) == H5T_ARRAY) { + int k, ndims; + hsize_t i, dims[H5S_MAX_RANK]; + + /* Get the array's base datatype for each element */ + memb = H5Tget_super(type); + size = H5Tget_size(memb); + ndims = H5Tget_array_ndims(type); + H5Tget_array_dims(type, dims, NULL); + assert(ndims >= 1 && ndims <= H5S_MAX_RANK); + + /* Calculate the number of array elements */ + for (k = 0, nelmts = 1; k < ndims; k++) + nelmts *= dims[k]; + + /* Print the opening bracket */ + h5tools_str_append(str, "%s", OPT(info->arr_pre, "[")); + + for (i = 0; i < nelmts; i++) { + if (i) + h5tools_str_append(str, "%s", + OPT(info->arr_sep, "," OPTIONAL_LINE_BREAK)); + + if (info->arr_linebreak && i && i % dims[ndims - 1] == 0) { + int x; + + h5tools_str_append(str, "%s", "\n"); + + /*need to indent some more here*/ + if (ctx->indent_level >= 0) + h5tools_str_append(str, "%s", OPT(info->line_pre, "")); + + for (x = 0; x < ctx->indent_level + 1; x++) + h5tools_str_append(str,"%s",OPT(info->line_indent,"")); + } /* end if */ + + ctx->indent_level++; + + /* Dump the array element */ + h5tools_sprint(str, info, container, memb, cp_vp + i * size, ctx); + + ctx->indent_level--; + } /* end for */ + + /* Print the closing bracket */ + h5tools_str_append(str, "%s", OPT(info->arr_suf, "]")); + H5Tclose(memb); + } else if (H5Tget_class(type) == H5T_VLEN) { + unsigned int i; + + /* Get the VL sequences's base datatype for each element */ + memb = H5Tget_super(type); + size = H5Tget_size(memb); + + /* Print the opening bracket */ + h5tools_str_append(str, "%s", OPT(info->vlen_pre, "(")); + + /* Get the number of sequence elements */ + nelmts = ((hvl_t *)cp_vp)->len; + + for (i = 0; i < nelmts; i++) { + if (i) + h5tools_str_append(str, "%s", + OPT(info->arr_sep, "," OPTIONAL_LINE_BREAK)); + +#ifdef LATER +/* Need to fix so VL data breaks at correct location on end of line -QAK */ + if (info->arr_linebreak && h5tools_str_len(str)>=info->line_ncols) { + int x; + + h5tools_str_append(str, "%s", "\n"); + + /* need to indent some more here */ + if (ctx->indent_level >= 0) + h5tools_str_append(str, "%s", OPT(info->line_pre, "")); + + for (x = 0; x < ctx->indent_level + 1; x++) + h5tools_str_append(str,"%s",OPT(info->line_indent,"")); + } /* end if */ +#endif /* LATER */ + + ctx->indent_level++; + + /* Dump the array element */ + h5tools_sprint(str, info, container, memb, + ((char *)(((hvl_t *)cp_vp)->p)) + i * size, ctx); + + ctx->indent_level--; + } /* end for */ + + h5tools_str_append(str, "%s", OPT(info->vlen_suf, ")")); + H5Tclose(memb); + } else { + /* All other types get printed as hexadecimal */ + size_t i; + + h5tools_str_append(str, "0x"); + n = H5Tget_size(type); + + for (i = 0; i < n; i++) + h5tools_str_append(str, "%02x", ucp_vp[i]); + } + + return h5tools_str_fmt(str, start, OPT(info->elmt_fmt, "%s")); +} + +/*------------------------------------------------------------------------- + * Function: h5tools_ncols + * + * Purpose: Count the number of columns in a string. This is the number + * of characters in the string not counting line-control + * characters. + * + * Return: Success: Width of string. + * + * Failure: 0 + * + * Programmer: Robb Matzke + * Tuesday, April 27, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static size_t +h5tools_ncols(const char *s) +{ + register size_t i; + + for (i = 0; *s; s++) + if (*s >= ' ') + i++; + + return i; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_simple_prefix + * + * Purpose: If ctx->need_prefix is set then terminate the current line + * (if applicable), calculate the prefix string, and display it + * at the start of a line. + * + * Return: void + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * Robb Matzke, 1999-09-29 + * If a new prefix is printed then the current element number is + * set back to zero. + *------------------------------------------------------------------------- + */ +static void +h5dump_simple_prefix(FILE *stream, const h5dump_t *info, + h5tools_context_t *ctx, hsize_t elmtno, int secnum) +{ + h5tools_str_t prefix; + size_t templength = 0; + int i, indentlevel = 0; + + memset(&prefix, 0, sizeof(h5tools_str_t)); + + if (!ctx->need_prefix) + return; + + /* Terminate previous line, if any */ + if (ctx->cur_column) { + fputs(OPT(info->line_suf, ""), stream); +#if 0 /*why?*/ + if (info->line_ncols != ctx->cur_column) { + putc('\n', stream); + } +#endif + putc('\n', stream); + fputs(OPT(info->line_sep, ""), stream); + } + + /* Calculate new prefix */ + h5tools_str_prefix(&prefix, info, elmtno, ctx->ndims, ctx->p_min_idx, + ctx->p_max_idx); + + /* Write new prefix to output */ + if (ctx->indent_level >= 0) { + indentlevel = ctx->indent_level; + } else { + /* this is because sometimes we dont print out all the header + * info for the data(like the tattr-2.ddl example. if that happens + * the ctx->indent_level a negative so we need to skip the above + * and just print out the default indent levels. */ + indentlevel = ctx->default_indent_level; + } + + if (elmtno == 0 && secnum == 0 && info->line_1st) + fputs(h5tools_str_fmt(&prefix, 0, info->line_1st), stream); + else if (secnum && info->line_cont) + fputs(h5tools_str_fmt(&prefix, 0, info->line_cont), stream); + else + fputs(h5tools_str_fmt(&prefix, 0, info->line_pre), stream); + + templength = h5tools_str_len(&prefix); + + for (i = 0; i < indentlevel; i++){ + fputs(h5tools_str_fmt(&prefix, 0, info->line_indent), stream); + templength += h5tools_str_len(&prefix); + } + + ctx->cur_column = ctx->prev_prefix_len = templength; + ctx->cur_elmt = 0; + ctx->need_prefix = 0; + + /* Free string */ + h5tools_str_close(&prefix); +} + +/*------------------------------------------------------------------------- + * Function: h5dump_simple_data + * + * Purpose: Prints some (NELMTS) data elements to output STREAM. The + * elements are stored in _MEM as type TYPE and are printed + * according to the format described in INFO. The CTX struct + * contains context information shared between calls to this + * function. The FLAGS is a bit field that indicates whether + * the data supplied in this call falls at the beginning or end + * of the total data to be printed (START_OF_DATA and + * END_OF_DATA). + * + * Return: void + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * Robb Matzke, 1999-06-04 + * The `container' argument is the optional dataset for + * reference types. + * + * Robb Matzke, 1999-09-29 + * Understands the `per_line' property which indicates that + * every Nth element should begin a new line. + * + *------------------------------------------------------------------------- + */ +static void +h5dump_simple_data(FILE *stream, const h5dump_t *info, hid_t container, + h5tools_context_t *ctx/*in,out*/, unsigned flags, + hsize_t nelmts, hid_t type, void *_mem) +{ + unsigned char *mem = (unsigned char*)_mem; + hsize_t i; /*element counter */ + char *s, *section; /*a section of output */ + int secnum; /*section sequence number */ + size_t size; /*size of each datum */ + size_t ncols=80; /*available output width */ + h5tools_str_t buffer; /*string into which to render */ + int multiline; /*datum was multiline */ + int elmt_counter=0; /*counts the # elements printed. + * I (ptl?) needed something that + * isnt going to get reset when a new + * line is formed. I'm going to use + * this var to count elements and + * break after we see a number equal + * to the ctx->size_last_dim. */ + + /* Setup */ + memset(&buffer, 0, sizeof(h5tools_str_t)); + size = H5Tget_size(type); + + if (info->line_ncols > 0) + ncols = info->line_ncols; + + h5dump_simple_prefix(stream, info, ctx, (hsize_t)0, 0); + + for (i = 0; i < nelmts; i++, ctx->cur_elmt++, elmt_counter++) { + /* Render the element */ + h5tools_str_reset(&buffer); + h5tools_sprint(&buffer, info, container, type, mem + i * size, ctx); + + if (i + 1 < nelmts || 0 == (flags & END_OF_DATA)) + h5tools_str_append(&buffer, "%s", OPT(info->elmt_suf1, ",")); + + s = h5tools_str_fmt(&buffer, 0, "%s"); + + /* + * If the element would split on multiple lines if printed at our + * current location... + */ + if (info->line_multi_new == 1 && + (ctx->cur_column + h5tools_ncols(s) + + strlen(OPT(info->elmt_suf2, " ")) + + strlen(OPT(info->line_suf, ""))) > ncols) { + if (ctx->prev_multiline) { + /* + * ... and the previous element also occupied more than one + * line, then start this element at the beginning of a line. + */ + ctx->need_prefix = TRUE; + } else if ((ctx->prev_prefix_len + h5tools_ncols(s) + + strlen(OPT(info->elmt_suf2, " ")) + + strlen(OPT(info->line_suf, ""))) <= ncols) { + /* + * ...but *could* fit on one line otherwise, then we + * should end the current line and start this element on its + * own line. + */ + ctx->need_prefix = TRUE; + } + } + + /* + * We need to break after each row of a dimension---> we should + * break at the end of the each last dimension well that is the + * way the dumper did it before + */ + if (info->arr_linebreak && ctx->cur_elmt) { + if (ctx->size_last_dim && (ctx->cur_elmt % ctx->size_last_dim) == 0) + ctx->need_prefix = TRUE; + + if (elmt_counter == ctx->size_last_dim) { + ctx->need_prefix = TRUE; + elmt_counter = 0; + } + } + + /* + * If the previous element occupied multiple lines and this element + * is too long to fit on a line then start this element at the + * beginning of the line. + */ + if (info->line_multi_new == 1 && ctx->prev_multiline && + (ctx->cur_column + h5tools_ncols(s) + + strlen(OPT(info->elmt_suf2, " ")) + + strlen(OPT(info->line_suf, ""))) > ncols) + ctx->need_prefix = TRUE; + + /* + * If too many elements have already been printed then we need to + * start a new line. + */ + if (info->line_per_line > 0 && ctx->cur_elmt >= info->line_per_line) + ctx->need_prefix = TRUE; + + /* + * Each OPTIONAL_LINE_BREAK embedded in the rendered string can cause + * the data to split across multiple lines. We display the sections + * one-at a time. + */ + for (secnum = 0, multiline = 0; + (section = strtok(secnum ? NULL : s, OPTIONAL_LINE_BREAK)); + secnum++) { + /* + * If the current section plus possible suffix and end-of-line + * information would cause the output to wrap then we need to + * start a new line. + */ + + /* + * Added the info->skip_first because the dumper does not want + * this check to happen for the first line + */ + if ((!info->skip_first || i) && + (ctx->cur_column + strlen(section) + + strlen(OPT(info->elmt_suf2, " ")) + + strlen(OPT(info->line_suf, ""))) > ncols) + ctx->need_prefix = 1; + + /* + * Print the prefix or separate the beginning of this element + * from the previous element. + */ + if (ctx->need_prefix) { + if (secnum) + multiline++; + + h5dump_simple_prefix(stream, info, ctx, i, secnum); + } else if ((i || ctx->continuation) && secnum == 0) { + fputs(OPT(info->elmt_suf2, " "), stream); + ctx->cur_column += strlen(OPT(info->elmt_suf2, " ")); + } + + /* Print the section */ + fputs(section, stream); + ctx->cur_column += strlen(section); + } + + ctx->prev_multiline = multiline; + } + + h5tools_str_close(&buffer); +} + +/*------------------------------------------------------------------------- + * Function: h5dump_simple_dset + * + * Purpose: Print some values from a dataset with a simple data space. + * This is a special case of h5dump_dset(). This function only + * intended for dumping datasets -- it does strip mining and + * some other things which are unnecessary for smaller objects + * such as attributes (to print small objects like attributes + * simply read the attribute and call h5dump_simple_mem()). + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, + hid_t p_type, int indentlevel) +{ + hid_t f_space; /*file data space */ + hsize_t elmtno, i; /*counters */ + int carry; /*counter carry value */ + hssize_t zero[8]; /*vector of zeros */ + unsigned flags; /*buffer extent flags */ + hsize_t total_size[H5S_MAX_RANK];/*total size of dataset*/ + + /* Print info */ + h5tools_context_t ctx; /*print context */ + size_t p_type_nbytes; /*size of memory type */ + hsize_t p_nelmts; /*total selected elmts */ + + /* Stripmine info */ + hsize_t sm_size[H5S_MAX_RANK]; /*stripmine size */ + hsize_t sm_nbytes; /*bytes per stripmine */ + hsize_t sm_nelmts; /*elements per stripmine*/ + unsigned char *sm_buf=NULL; /*buffer for raw data */ + hid_t sm_space; /*stripmine data space */ + + /* Hyperslab info */ + hssize_t hs_offset[H5S_MAX_RANK];/*starting offset */ + hsize_t hs_size[H5S_MAX_RANK]; /*size this pass */ + hsize_t hs_nelmts; /*elements in request */ + + /* VL data special information */ + unsigned vl_data=0; /* Whether the dataset contains VL datatypes */ + +#if 0 + hsize_t dim_n_size; +#endif + + /* + * Check that everything looks okay. The dimensionality must not be too + * great and the dimensionality of the items selected for printing must + * match the dimensionality of the dataset. + */ + memset(&ctx, 0, sizeof(ctx)); + ctx.indent_level = indentlevel; + ctx.need_prefix = 1; + f_space = H5Dget_space(dset); + ctx.ndims = H5Sget_simple_extent_ndims(f_space); + + if ((size_t)ctx.ndims > NELMTS(sm_size)) + return -1; + + /* Assume entire data space to be printed */ + if (ctx.ndims > 0) + for (i = 0; i < (hsize_t)ctx.ndims; i++) + ctx.p_min_idx[i] = 0; + + H5Sget_simple_extent_dims(f_space, total_size, NULL); + + if (ctx.ndims > 0) { + for (i = 0, p_nelmts = 1; i < (hsize_t)ctx.ndims; i++) + p_nelmts *= total_size[i]; + } else { + p_nelmts = 1; + } + + if (p_nelmts == 0) { + H5Sclose(f_space); + return 0; /*nothing to print*/ + } + + ctx.size_last_dim = total_size[ctx.ndims - 1]; + + /* Check if we have VL data in the dataset's datatype */ + if(H5Tdetect_class(p_type,H5T_VLEN)==TRUE) + vl_data=TRUE; + + /* + * Determine the strip mine size and allocate a buffer. The strip mine is + * a hyperslab whose size is manageable. + */ + p_type_nbytes = H5Tget_size(p_type); + + if (ctx.ndims > 0) { + for (i = ctx.ndims, sm_nbytes = p_type_nbytes; i > 0; --i) { + sm_size[i - 1] = MIN(total_size[i - 1], H5DUMP_BUFSIZE / sm_nbytes); + sm_nbytes *= sm_size[i - 1]; + assert(sm_nbytes > 0); + } + } else { + sm_nbytes = p_type_nbytes; + } + + assert(sm_nbytes == (hsize_t)((size_t)sm_nbytes)); /*check for overflow*/ + sm_buf = malloc((size_t)sm_nbytes); + sm_nelmts = sm_nbytes / p_type_nbytes; + sm_space = H5Screate_simple(1, &sm_nelmts, NULL); + + /* The stripmine loop */ + memset(hs_offset, 0, sizeof hs_offset); + memset(zero, 0, sizeof zero); + + for (elmtno = 0; elmtno < p_nelmts; elmtno += hs_nelmts) { + /* Calculate the hyperslab size */ + if (ctx.ndims > 0) { + for (i = 0, hs_nelmts = 1; i < (hsize_t)ctx.ndims; i++) { + hs_size[i] = MIN(total_size[i] - hs_offset[i], sm_size[i]); + ctx.p_max_idx[i] = ctx.p_min_idx[i] + hs_size[i]; + hs_nelmts *= hs_size[i]; + } + + H5Sselect_hyperslab(f_space, H5S_SELECT_SET, hs_offset, NULL, + hs_size, NULL); + H5Sselect_hyperslab(sm_space, H5S_SELECT_SET, zero, NULL, + &hs_nelmts, NULL); + } else { + H5Sselect_all(f_space); + H5Sselect_all(sm_space); + hs_nelmts = 1; + } + + /* Read the data */ + if (H5Dread(dset, p_type, sm_space, f_space, H5P_DEFAULT, sm_buf) < 0) { + H5Sclose(f_space); + H5Sclose(sm_space); + free(sm_buf); + return -1; + } + + /* Print the data */ + flags = (elmtno == 0) ? START_OF_DATA : 0; + flags |= ((elmtno + hs_nelmts) >= p_nelmts) ? END_OF_DATA : 0; + h5dump_simple_data(stream, info, dset, &ctx, flags, hs_nelmts, + p_type, sm_buf); + + /* Reclaim any VL memory, if necessary */ + if(vl_data) + H5Dvlen_reclaim(p_type,sm_space,H5P_DEFAULT,sm_buf); + + /* Calculate the next hyperslab offset */ + for (i = ctx.ndims, carry = 1; i > 0 && carry; --i) { + ctx.p_min_idx[i - 1] = ctx.p_max_idx[i - 1]; + hs_offset[i - 1] += hs_size[i - 1]; + + if (hs_offset[i - 1] == (hssize_t)total_size[i - 1]) + hs_offset[i-1] = 0; + else + carry = 0; + } + + ctx.continuation++; + } + + /* Terminate the output */ + if (ctx.cur_column) { + fputs(OPT(info->line_suf, ""), stream); + putc('\n', stream); + fputs(OPT(info->line_sep, ""), stream); + } + + H5Sclose(sm_space); + H5Sclose(f_space); + free(sm_buf); + return 0; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_simple_mem + * + * Purpose: Print some values from memory with a simple data space. + * This is a special case of h5dump_mem(). + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +h5dump_simple_mem(FILE *stream, const h5dump_t *info, hid_t obj_id, hid_t type, + hid_t space, void *mem, int indentlevel) +{ + hsize_t i; /*counters */ + hsize_t nelmts; /*total selected elmts */ + h5tools_context_t ctx; /*printing context */ + + /* + * Check that everything looks okay. The dimensionality must not be too + * great and the dimensionality of the items selected for printing must + * match the dimensionality of the dataset. + */ + memset(&ctx, 0, sizeof(ctx)); + ctx.ndims = H5Sget_simple_extent_ndims(space); + + if ((size_t)ctx.ndims > NELMTS(ctx.p_min_idx)) + return -1; + + ctx.indent_level = indentlevel; + ctx.need_prefix = 1; + + /* Assume entire data space to be printed */ + for (i = 0; i < (hsize_t)ctx.ndims; i++) + ctx.p_min_idx[i] = 0; + + H5Sget_simple_extent_dims(space, ctx.p_max_idx, NULL); + + for (i = 0, nelmts = 1; ctx.ndims != 0 && i < (hsize_t)ctx.ndims; i++) + nelmts *= ctx.p_max_idx[i] - ctx.p_min_idx[i]; + + if (nelmts == 0) + return 0; /*nothing to print*/ + + ctx.size_last_dim = ctx.p_max_idx[ctx.ndims - 1]; + + /* Print it */ + h5dump_simple_data(stream, info, obj_id, &ctx, + START_OF_DATA | END_OF_DATA, nelmts, type, mem); + + /* Terminate the output */ + if (ctx.cur_column) { + fputs(OPT(info->line_suf, ""), stream); + putc('\n', stream); + fputs(OPT(info->line_sep, ""), stream); + } + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_fixtype + * + * Purpose: Given a file data type choose a memory data type which is + * appropriate for printing the data. + * + * Return: Success: Memory data type + * + * Failure: FAIL + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * Robb Matzke, 1999-06-04 + * Added support for references. + * + *------------------------------------------------------------------------- + */ +hid_t +h5dump_fixtype(hid_t f_type) +{ + hid_t m_type = FAIL, f_memb; + hid_t *memb = NULL; + char **name = NULL; + int nmembs = 0, i; + int ndims; + hsize_t dim[H5S_MAX_RANK]; + size_t size, offset; + hid_t array_base; + /* H5T_str_t strpad; */ + + size = H5Tget_size(f_type); + + switch (H5Tget_class(f_type)) { + case H5T_INTEGER: + /* + * Use the smallest native integer type of the same sign as the file + * such that the memory type is at least as large as the file type. + * If there is no memory type large enough then use the largest + * memory type available. + */ + if (size <= sizeof(char)) { + m_type = H5Tcopy(H5T_NATIVE_SCHAR); + } else if (size <= sizeof(short)) { + m_type = H5Tcopy(H5T_NATIVE_SHORT); + } else if (size <= sizeof(int)) { + m_type = H5Tcopy(H5T_NATIVE_INT); + } else if (size <= sizeof(long)) { + m_type = H5Tcopy(H5T_NATIVE_LONG); + } else { + m_type = H5Tcopy(H5T_NATIVE_LLONG); + } + + H5Tset_sign(m_type, H5Tget_sign(f_type)); + break; + + case H5T_FLOAT: + /* + * Use the smallest native floating point type available such that + * its size is at least as large as the file type. If there is not + * native type large enough then use the largest native type. + */ + if (size <= sizeof(float)) { + m_type = H5Tcopy(H5T_NATIVE_FLOAT); + } else if (size <= sizeof(double)) { + m_type = H5Tcopy(H5T_NATIVE_DOUBLE); + } else { + m_type = H5Tcopy(H5T_NATIVE_LDOUBLE); + } + + break; + + case H5T_STRING: + /* + * This is needed because the function in dumputil.c is the case where + * strDUAction == TRUE. if it is false we will do the original action + * here. + */ + m_type = H5Tcopy(f_type); + H5Tset_cset(m_type, H5T_CSET_ASCII); + break; + + case H5T_COMPOUND: + /* + * We have to do this in two steps. The first step scans the file + * type and converts the members to native types and remembers all + * their names and sizes, computing the size of the memory compound + * type at the same time. Then we create the memory compound type + * and add the members. + */ + nmembs = H5Tget_nmembers(f_type); + assert(nmembs>0); + memb = calloc((size_t)nmembs, sizeof(hid_t)); + name = calloc((size_t)nmembs, sizeof(char *)); + + for (i = 0, size = 0; i < nmembs; i++) { + /* Get the member type and fix it */ + f_memb = H5Tget_member_type(f_type, i); + memb[i] = h5dump_fixtype(f_memb); + H5Tclose(f_memb); + + if (memb[i] < 0) + goto done; + + /* Get the member name */ + name[i] = H5Tget_member_name(f_type, i); + + if (name[i] == NULL) + goto done; + + /* + * Compute the new offset so each member is aligned on a byte + * boundary which is the same as the member size. + */ + size = ALIGN(size, H5Tget_size(memb[i])) + H5Tget_size(memb[i]); + } + + m_type = H5Tcreate(H5T_COMPOUND, size); + + for (i = 0, offset = 0; i < nmembs; i++) { + if (offset) + offset = ALIGN(offset, H5Tget_size(memb[i])); + + H5Tinsert(m_type, name[i], offset, memb[i]); + offset += H5Tget_size(memb[i]); + } + + break; + + case H5T_ARRAY: + /* Get the array information */ + ndims = H5Tget_array_ndims(f_type); + H5Tget_array_dims(f_type, dim, NULL); + + /* Get the array's base type and convert it to the printable version */ + f_memb = H5Tget_super(f_type); + array_base = h5dump_fixtype(f_memb); + + /* Copy the array */ + m_type = H5Tarray_create(array_base, ndims, dim, NULL); + + /* Close the temporary datatypes */ + H5Tclose(array_base); + H5Tclose(f_memb); + break; + + case H5T_VLEN: + /* Get the VL sequence's base type and convert it to the printable version */ + f_memb = H5Tget_super(f_type); + array_base = h5dump_fixtype(f_memb); + + /* Copy the VL type */ + m_type = H5Tvlen_create(array_base); + + /* Close the temporary datatypes */ + H5Tclose(array_base); + H5Tclose(f_memb); + break; + + case H5T_ENUM: + case H5T_REFERENCE: + case H5T_OPAQUE: + /* Same as file type */ + m_type = H5Tcopy(f_type); + break; + + case H5T_BITFIELD: + /* + * Same as the file except the offset is set to zero and the byte + * order is set to little endian. + */ + m_type = H5Tcopy(f_type); + H5Tset_offset(m_type, 0); + H5Tset_order(m_type, H5T_ORDER_LE); + break; + + case H5T_TIME: + /* + * These type classes are not implemented yet. + */ + break; + + default: + /* What the heck? */ + break; + } + + done: + /* Clean up temp buffers */ + if (memb && name) { + register int j; + + for (j = 0; j < nmembs; j++) { + if (memb[j] >= 0) + H5Tclose(memb[j]); + + if (name[j]) + free(name[j]); + } + + free(memb); + free(name); + } + + return m_type; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_dset + * + * Purpose: Print some values from a dataset DSET to the file STREAM + * after converting all types to P_TYPE (which should be a + * native type). If P_TYPE is a negative value then it will be + * computed from the dataset type using only native types. + * + * Note: This function is intended only for datasets since it does + * some things like strip mining which are unnecessary for + * smaller objects such as attributes. The easiest way to print + * small objects is to read the object into memory and call + * h5dump_mem(). + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * Robb Matzke, 1999-06-07 + * If info->raw is set then the memory datatype will be the same + * as the file datatype. + * + *------------------------------------------------------------------------- + */ +int +h5dump_dset(FILE *stream, const h5dump_t *info, hid_t dset, hid_t _p_type, + int indentlevel) +{ + hid_t f_space; + hid_t p_type = _p_type; + hid_t f_type; + int status = -1; + h5dump_t info_dflt; + + /* Use default values */ + if (!stream) + stream = stdout; + + if (!info) { + memset(&info_dflt, 0, sizeof info_dflt); + info = &info_dflt; + } + + if (p_type < 0) { + f_type = H5Dget_type(dset); + + if (info->raw) + p_type = H5Tcopy(f_type); + else + p_type = h5dump_fixtype(f_type); + + H5Tclose(f_type); + + if (p_type < 0) + goto done; + } + + /* Check the data space */ + f_space = H5Dget_space(dset); + + /* Print the data */ + if (H5Sis_simple(f_space) > 0) { + status = h5dump_simple_dset(rawdatastream, info, dset, p_type, + indentlevel); + } + + /* Close the dataspace */ + H5Sclose(f_space); + +done: + if (p_type != _p_type) + H5Tclose(p_type); + + return status; +} + +/*------------------------------------------------------------------------- + * Function: h5dump_mem + * + * Purpose: Displays the data contained in MEM. MEM must have the + * specified data TYPE and SPACE. Currently only simple data + * spaces are allowed and only the `all' selection. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Wednesday, January 20, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +h5dump_mem(FILE *stream, const h5dump_t *info, hid_t obj_id, hid_t type, hid_t space, + void *mem,int indentlevel) +{ + h5dump_t info_dflt; + + /* Use default values */ + if (!stream) + stream = stdout; + + if (!info) { + memset(&info_dflt, 0, sizeof info_dflt); + info = &info_dflt; + } + + /* Check the data space */ + if (H5Sis_simple(space) <= 0) + return -1; + + return h5dump_simple_mem(stream, info, obj_id, type, space, mem, indentlevel); +} + +/************************************************************************* + + from h5dumputil.c + + *************************************************************************/ + +/*------------------------------------------------------------------------- + * Function: indentation + * + * Purpose: Print spaces for indentation + * + * Return: void + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void indentation(int x) +{ + if (x < nCols) { + while (x-- > 0) + printf(" "); + } else { + fprintf(stderr, "error: the indentation exceeds the number of cols.\n"); + exit(1); + } +} + +/*------------------------------------------------------------------------- + * Function: print_version + * + * Purpose: Print the program name and the version information which is + * defined the same as the HDF5 library version. + * + * Return: void + * + * Programmer: unknown + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +print_version(const char *progname) +{ + printf("%s: Version %u.%u.%u%s%s\n", + progname, H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE, + H5_VERS_SUBRELEASE[0] ? "-" : "", H5_VERS_SUBRELEASE); +} + +/* + * + * THE FUNCTIONS BELOW ARE FROM THE H5FINSHD.C FILE + * + */ + +/*------------------------------------------------------------------------- + * Function: init_table + * + * Purpose: allocate and initialize tables for shared groups, datasets, + * and committed types + * + * Return: void + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +init_table(table_t** temp) +{ + int i; + table_t *table = malloc(sizeof(table_t)); + + table->size = 20; + table->nobjs = 0; + table->objs = malloc(table->size * sizeof(obj_t)); + + for (i = 0; i < table->size; i++) { + table->objs[i].objno[0] = table->objs[i].objno[1] = 0; + table->objs[i].displayed = 0; + table->objs[i].recorded = 0; + table->objs[i].objflag = 0; + } + + *temp = table; +} + +/*------------------------------------------------------------------------- + * Function: init_prefix + * + * Purpose: allocate and initialize prefix + * + * Return: void + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +init_prefix(char **prefix, int prefix_len) +{ + assert(prefix_len > 0); + *prefix = calloc((size_t)prefix_len, 1); +} + +/*------------------------------------------------------------------------- + * Function: free_table + * + * Purpose: free tables for shared groups, datasets, + * and committed types + * + * Return: void + * + * Programmer: Paul Harten + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +free_table(table_t **table) +{ + HDfree((*table)->objs); +} + +/*------------------------------------------------------------------------- + * Function: search_obj + * + * Purpose: search the object specified by objno in the table + * + * Return: an integer, the location of the object + * -1 if object is not found + * + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +search_obj(table_t *table, unsigned long *objno) +{ + register int i; + + for (i = 0; i < table->nobjs; i++) + if (table->objs[i].objno[0] == *objno && table->objs[i].objno[1] == *(objno + 1)) + return i; + + return -1; +} + +/*------------------------------------------------------------------------- + * Function: add_obj + * + * Purpose: add a shared object to the table + * realloc the table if necessary + * + * Return: void + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +add_obj(table_t *table, unsigned long *objno, char *objname) +{ + register int i; + + if (table->nobjs == table->size) { + table->size *= 2; + table->objs = realloc(table->objs, table->size*sizeof(obj_t)); + + for (i = table->nobjs; i < table->size; i++) { + table->objs[i].objno[0] = table->objs[i].objno[1] = 0; + table->objs[i].displayed = 0; + table->objs[i].recorded = 0; + table->objs[i].objflag = 0; + } + } + + i = table->nobjs++; + table->objs[i].objno[0] = *objno; + table->objs[i].objno[1] = *(objno + 1); + strcpy(table->objs[i].objname, objname); +} + +/*------------------------------------------------------------------------- + * Function: Find_objs + * + * Purpose: Find objects, committed types and store them in tables + * + * Return: Success: SUCCEED + * + * Failure: FAIL + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +find_objs(hid_t group, const char *name, void *op_data) +{ + hid_t obj, type; + H5G_stat_t statbuf; + char *tmp; + find_objs_t *info = (find_objs_t*)op_data; + register int i; + + if (info->threshold > 1) + /*will get an infinite loop if greater than 1*/ + return FAIL; + + H5Gget_objinfo(group, name, TRUE, &statbuf); + + tmp = malloc(strlen(info->prefix) + strlen(name) + 2); + strcpy(tmp, info->prefix); + + switch (statbuf.type) { + case H5G_GROUP: + if ((obj = H5Gopen(group, name)) >= 0) { + if (info->prefix_len < (int)(strlen(info->prefix) + strlen(name) + 2)) { + info->prefix_len *= 2; + info->prefix = realloc(info->prefix, + info->prefix_len * sizeof(char)); + } + + strcat(strcat(info->prefix,"/"), name); + + if (statbuf.nlink > info->threshold) { + if (search_obj(info->group_table, statbuf.objno) < 0) { + add_obj(info->group_table, statbuf.objno, info->prefix); + H5Giterate(obj, ".", NULL, find_objs, (void *)info); + } + } else { + H5Giterate (obj, ".", NULL, find_objs, (void *)info); + } + + strcpy(info->prefix, tmp); + H5Gclose (obj); + } else { + info->status = 1; + } + + break; + + case H5G_DATASET: + strcat(tmp,"/"); + strcat(tmp,name); /* absolute name of the data set */ + + if (statbuf.nlink > info->threshold && + search_obj(info->dset_table, statbuf.objno) < 0) + add_obj(info->dset_table, statbuf.objno, tmp); + + if ((obj = H5Dopen (group, name)) >= 0) { + type = H5Dget_type(obj); + + if (H5Tcommitted(type) > 0) { + H5Gget_objinfo(type, ".", TRUE, &statbuf); + + if (search_obj (info->type_table, statbuf.objno) < 0) { + add_obj(info->type_table, statbuf.objno, tmp); + info->type_table->objs[info->type_table->nobjs - 1].objflag = 0; + } + } + + H5Tclose(type); + H5Dclose (obj); + } else { + info->status = 1; + } + + break; + + case H5G_TYPE: + strcat(tmp,"/"); + strcat(tmp,name); /* absolute name of the type */ + i = search_obj(info->type_table, statbuf.objno); + + if (i < 0) { + add_obj(info->type_table, statbuf.objno, tmp) ; + + /* named data type */ + info->type_table->objs[info->type_table->nobjs-1].recorded = 1; + + /* named data type */ + info->type_table->objs[info->type_table->nobjs-1].objflag = 1; + } else { + strcpy (info->type_table->objs[i].objname, tmp); + info->type_table->objs[i].recorded = 1; + + /* named data type */ + info->type_table->objs[info->type_table->nobjs-1].objflag = 1; + } + + break; + + default: + break; + } + + free(tmp); + return SUCCEED; +} + +/*------------------------------------------------------------------------- + * Function: dump_tables + * + * Purpose: display the contents of tables for debugging purposes + * + * Return: void + * + * Programmer: Ruey-Hsia Li + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +dump_table(char* tablename, table_t *table) +{ + register int i; + + printf("%s: # of entries = %d\n", tablename,table->nobjs); + + for (i = 0; i < table->nobjs; i++) + printf("%lu %lu %s %d\n", table->objs[i].objno[0], + table->objs[i].objno[1], + table->objs[i].objname, + table->objs[i].objflag); +} + +/*------------------------------------------------------------------------- + * Function: get_table_idx + * + * Purpose: Determine if objects are in a link loop + * + * Return: Success: table index of object detected to be in loop + * + * Failure: FAIL + * + * Programmer: Paul Harten + * + *------------------------------------------------------------------------- + */ +int +get_table_idx(table_t *table, unsigned long *objno) +{ + return search_obj(table, objno); +} + +/*------------------------------------------------------------------------- + * Function: Get table flag setting + * + * Purpose: Keep the structures and variables used private to + * this file. + * + * Return: Success: Boolean setting of the i'th element of the + * object table flag + * + * Failure: FAIL + * + * Programmer: Paul Harten + * + *------------------------------------------------------------------------- + */ +int +get_tableflag(table_t *table, int idx) +{ + return table->objs[idx].objflag; +} + +/*------------------------------------------------------------------------- + * Function: Set table flag setting + * + * Purpose: Keep the structures and variables used private to + * this file. + * + * Return: Success: Boolean setting of the i'th element of the + * object table flag + * + * Failure: FAIL + * + * Programmer: Paul Harten + * + *------------------------------------------------------------------------- + */ +int +set_tableflag(table_t *table, int idx) +{ + table->objs[idx].objflag = TRUE; + return SUCCEED; +} + +/*------------------------------------------------------------------------- + * Function: get_objectname + * + * Purpose: Get name of i'th object in table + * + * Return: Success: strdup() of object name character string + * + * Failure: NULL + * + * Programmer: Paul Harten + * + *------------------------------------------------------------------------- + */ +char * +get_objectname(table_t *table, int idx) +{ + return strdup(table->objs[idx].objname); +} + +/*------------------------------------------------------------------------- + * Function: h5dump_fopen + * + * Purpose: Attempts to open a file with various VFL drivers. + * + * Return: Success: a file id for the opened file. If + * DRIVERNAME is non-null then the first + * DRIVERNAME_SIZE-1 characters of the driver + * name are copied into the DRIVERNAME array + * and null terminated. + * + * Failure: -1. If DRIVERNAME is non-null then the + * first byte is set to the null terminator. + * + * Modifications: + * Robb Matzke, 2000-06-23 + * We only have to initialize driver[] on the first call, + * thereby preventing memory leaks from repeated calls to + * H5Pcreate(). + * + * Robb Matzke, 2000-06-23 + * Added DRIVERNAME_SIZE arg to prevent overflows when + * writing to DRIVERNAME. + * + * Robb Matzke, 2000-06-23 + * Added test to prevent coredump when the file could not be + * opened by any driver. + * + * Robb Matzke, 2000-06-23 + * Changed name from H5ToolsFopen() so it jives better with + * the names we already have at the top of this source file. + * + * Thomas Radke, 2000-09-12 + * Added Stream VFD to the driver[] array. + * + * Bill Wendling, 2001-01-10 + * Changed macro behavior so that if we have a version other + * than 1.2.x (i.e., > 1.2), then we do the drivers check. + *------------------------------------------------------------------------- + */ +hid_t +h5dump_fopen(const char *fname, char *drivername, size_t drivername_size) +{ + static struct { + const char *name; + hid_t fapl; + } driver[16]; + static int ndrivers = 0; + hid_t fid = -1; +#ifndef VERSION12 + hid_t fapl = H5P_DEFAULT; +#endif /* !VERSION12 */ + int drivernum; + + if (!ndrivers) { + /* Build a list of file access property lists which we should try + * when opening the file. Eventually we'd like some way for the + * user to augment/replace this list interactively. */ + driver[ndrivers].name = "sec2"; + driver[ndrivers].fapl = H5P_DEFAULT; + ndrivers++; + +#ifndef VERSION12 + driver[ndrivers].name = "family"; + driver[ndrivers].fapl = fapl = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fapl_family(fapl, (hsize_t)0, H5P_DEFAULT); + ndrivers++; + + driver[ndrivers].name = "split"; + driver[ndrivers].fapl = fapl = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fapl_split(fapl, "-m.h5", H5P_DEFAULT, "-r.h5", H5P_DEFAULT); + ndrivers++; + + driver[ndrivers].name = "multi"; + driver[ndrivers].fapl = fapl = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fapl_multi(fapl, NULL, NULL, NULL, NULL, TRUE); + ndrivers++; + +#ifdef H5_HAVE_STREAM + driver[ndrivers].name = "stream"; + driver[ndrivers].fapl = fapl = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fapl_stream(fapl, NULL); + ndrivers++; +#endif /* H5_HAVE_STREAM */ +#endif /* !VERSION12 */ + } + + /* Try to open the file using each of the drivers */ + for (drivernum = 0; drivernum < ndrivers; drivernum++) { + H5E_BEGIN_TRY { + fid = H5Fopen(fname, H5F_ACC_RDONLY, driver[drivernum].fapl); + } H5E_END_TRY; + + if (fid >= 0) + break; + } + + /* Save the driver name */ + if (drivername && drivername_size){ + if (fid >= 0) { + strncpy(drivername, driver[drivernum].name, drivername_size); + drivername[drivername_size - 1] = '\0'; + } else { + drivername[0] = '\0'; /*no file opened*/ + } + } + + return fid; +} diff --git a/tools/lib/h5tools.h b/tools/lib/h5tools.h new file mode 100644 index 0000000..2d04539 --- /dev/null +++ b/tools/lib/h5tools.h @@ -0,0 +1,517 @@ +/* + * Copyright (c) 1998-2001 National Center for Supercomputing Applications + * All rights reserved. + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Purpose: Support functions for the various tools. + */ +#ifndef H5TOOLS_H__ +#define H5TOOLS_H__ + +#include "hdf5.h" + +#if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 2 +#define VERSION12 +#endif /* H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 2 */ + +#define ESCAPE_HTML 1 + +#define OPT(X,S) ((X) ? (X) : (S)) + +/* + * Information about how to format output. + */ +typedef struct h5dump_t { + /* + * Fields associated with formatting numeric data. If a datatype matches + * multiple formats based on its size, then the first applicable format + * from this list is used. However, if `raw' is non-zero then dump all + * data in hexadecimal format without translating from what appears on + * disk. + * + * raw: If set then print all data as hexadecimal without + * performing any conversion from disk. + * + * fmt_raw: The printf() format for each byte of raw data. The + * default is `%02x'. + * + * fmt_int: The printf() format to use when rendering data which is + * typed `int'. The default is `%d'. + * + * fmt_uint: The printf() format to use when rendering data which is + * typed `unsigned'. The default is `%u'. + * + * fmt_schar: The printf() format to use when rendering data which is + * typed `signed char'. The default is `%d'. This format is + * used ony if the `ascii' field is zero. + * + * fmt_uchar: The printf() format to use when rendering data which is + * typed `unsigned char'. The default is `%u'. This format + * is used only if the `ascii' field is zero. + * + * fmt_short: The printf() format to use when rendering data which is + * typed `short'. The default is `%d'. + * + * fmt_ushort: The printf() format to use when rendering data which is + * typed `unsigned short'. The default is `%u'. + * + * fmt_long: The printf() format to use when rendering data which is + * typed `long'. The default is `%ld'. + * + * fmt_ulong: The printf() format to use when rendering data which is + * typed `unsigned long'. The default is `%lu'. + * + * fmt_llong: The printf() format to use when rendering data which is + * typed `long long'. The default depends on what printf() + * format is available to print this datatype. + * + * fmt_ullong: The printf() format to use when rendering data which is + * typed `unsigned long long'. The default depends on what + * printf() format is available to print this datatype. + * + * fmt_double: The printf() format to use when rendering data which is + * typed `double'. The default is `%g'. + * + * fmt_float: The printf() format to use when rendering data which is + * typed `float'. The default is `%g'. + * + * ascii: If set then print 1-byte integer values as an ASCII + * character (no quotes). If the character is one of the + * standard C escapes then print the escaped version. If + * the character is unprintable then print a 3-digit octal + * escape. If `ascii' is zero then then 1-byte integers are + * printed as numeric values. The default is zero. + * + * str_locale: Determines how strings are printed. If zero then strings + * are printed like in C except. If set to ESCAPE_HTML then + * strings are printed using HTML encoding where each + * character not in the class [a-zA-Z0-9] is substituted + * with `%XX' where `X' is a hexadecimal digit. + * + * str_repeat: If set to non-zero then any character value repeated N + * or more times is printed as 'C'*N + * + * Numeric data is also subject to the formats for individual elements. + */ + hbool_t raw; + const char *fmt_raw; + const char *fmt_int; + const char *fmt_uint; + const char *fmt_schar; + const char *fmt_uchar; + const char *fmt_short; + const char *fmt_ushort; + const char *fmt_long; + const char *fmt_ulong; + const char *fmt_llong; + const char *fmt_ullong; + const char *fmt_double; + const char *fmt_float; + int ascii; + int str_locale; + int str_repeat; + + /* + * Fields associated with compound array members. + * + * pre: A string to print at the beginning of each array. The + * default value is the left square bracket `['. + * + * sep: A string to print between array values. The default + * value is a ",\001" ("\001" indicates an optional line + * break). + * + * suf: A string to print at the end of each array. The default + * value is a right square bracket `]'. + * + * linebreaks: a boolean value to determine if we want to break the line + * after each row of an array. + */ + const char *arr_pre; + const char *arr_sep; + const char *arr_suf; + int arr_linebreak; + + /* + * Fields associated with compound data types. + * + * name: How the name of the struct member is printed in the + * values. By default the name is not printed, but a + * reasonable setting might be "%s=" which prints the name + * followed by an equal sign and then the value. + * + * sep: A string that separates one member from another. The + * default is ", \001" (the \001 indicates an optional + * line break to allow structs to span multiple lines of + * output). + * + * pre: A string to print at the beginning of a compound type. + * The default is a left curly brace. + * + * suf: A string to print at the end of each compound type. The + * default is right curly brace. + * + * end: a string to print after we reach the last element of + * each compound type. prints out before the suf. + */ + const char *cmpd_name; + const char *cmpd_sep; + const char *cmpd_pre; + const char *cmpd_suf; + const char *cmpd_end; + + /* + * Fields associated with vlen data types. + * + * sep: A string that separates one member from another. The + * default is ", \001" (the \001 indicates an optional + * line break to allow structs to span multiple lines of + * output). + * + * pre: A string to print at the beginning of a vlen type. + * The default is a left parentheses. + * + * suf: A string to print at the end of each vlen type. The + * default is a right parentheses. + * + * end: a string to print after we reach the last element of + * each compound type. prints out before the suf. + */ + const char *vlen_sep; + const char *vlen_pre; + const char *vlen_suf; + const char *vlen_end; + + /* + * Fields associated with the individual elements. + * + * fmt: A printf(3c) format to use to print the value string + * after it has been rendered. The default is "%s". + * + * suf1: This string is appended to elements which are followed by + * another element whether the following element is on the + * same line or the next line. The default is a comma. + * + * suf2: This string is appended (after `suf1') to elements which + * are followed on the same line by another element. The + * default is a single space. + */ + const char *elmt_fmt; + const char *elmt_suf1; + const char *elmt_suf2; + + /* + * Fields associated with the index values printed at the left edge of + * each line of output. + * + * n_fmt: Each index value is printed according to this printf(3c) + * format string which should include a format for a long + * integer. The default is "%lu". + * + * sep: Each integer in the index list will be separated from the + * others by this string, which defaults to a comma. + * + * fmt: After the index values are formated individually and + * separated from one another by some string, the entire + * resulting string will be formated according to this + * printf(3c) format which should include a format for a + * character string. The default is "%s". + */ + const char *idx_n_fmt; /*index number format */ + const char *idx_sep; /*separator between numbers */ + const char *idx_fmt; /*entire index format */ + + /* + * Fields associated with entire lines. + * + * ncols: Number of columns per line defaults to 80. + * + * per_line: If this field has a positive value then every Nth element + * will be printed at the beginning of a line. + * + * pre: Each line of output contains an optional prefix area + * before the data. This area can contain the index for the + * first datum (represented by `%s') as well as other + * constant text. The default value is `%s'. + * + * 1st: This is the format to print at the beginning of the first + * line of output. The default value is the current value of + * `pre' described above. + * + * cont: This is the format to print at the beginning of each line + * which was continued because the line was split onto + * multiple lines. This often happens with compound + * data which is longer than one line of output. The default + * value is the current value of the `pre' field + * described above. + * + * suf: This character string will be appended to each line of + * output. It should not contain line feeds. The default + * is the empty string. + * + * sep: A character string to be printed after every line feed + * defaulting to the empty string. It should end with a + * line feed. + * + * multi_new: Indicates the algorithm to use when data elements tend to + * occupy more than one line of output. The possible values + * are (zero is the default): + * + * 0: No consideration. Each new element is printed + * beginning where the previous element ended. + * + * 1: Print the current element beginning where the + * previous element left off. But if that would result + * in the element occupying more than one line and it + * would only occupy one line if it started at the + * beginning of a line, then it is printed at the + * beginning of the next line. + * + * multi_new: If an element is continued onto additional lines then + * should the following element begin on the next line? The + * default is to start the next element on the same line + * unless it wouldn't fit. + * + * indentlevel: a string that shows how far to indent if extra spacing + * is needed. dumper uses it. + */ + int line_ncols; /*columns of output */ + size_t line_per_line; /*max elements per line */ + const char *line_pre; /*prefix at front of each line */ + const char *line_1st; /*alternate pre. on first line */ + const char *line_cont; /*alternate pre. on continuation*/ + const char *line_suf; /*string to append to each line */ + const char *line_sep; /*separates lines */ + int line_multi_new; /*split multi-line outputs? */ + const char *line_indent; /*for extra identation if we need it*/ + + /*used to skip the first set of checks for line length*/ + int skip_first; + + /*flag used to hide or show the file number for obj refs*/ + int obj_hidefileno; + + /*string used to format the output for the obje refs*/ + const char *obj_format; + + /*flag used to hide or show the file number for dataset regions*/ + int dset_hidefileno; + + /*string used to format the output for the dataset regions*/ + const char *dset_format; + + const char *dset_blockformat_pre; + const char *dset_ptformat_pre; + const char *dset_ptformat; + +} h5dump_t; + + +typedef struct dump_header{ + const char *name; + const char *filebegin; + const char *fileend; + const char *bootblockbegin; + const char *bootblockend; + const char *groupbegin; + const char *groupend; + const char *datasetbegin; + const char *datasetend; + const char *attributebegin; + const char *attributeend; + const char *datatypebegin; + const char *datatypeend; + const char *dataspacebegin; + const char *dataspaceend; + const char *databegin; + const char *dataend; + const char *softlinkbegin; + const char *softlinkend; + + const char *fileblockbegin; + const char *fileblockend; + const char *bootblockblockbegin; + const char *bootblockblockend; + const char *groupblockbegin; + const char *groupblockend; + const char *datasetblockbegin; + const char *datasetblockend; + const char *attributeblockbegin; + const char *attributeblockend; + const char *datatypeblockbegin; + const char *datatypeblockend; + const char *dataspaceblockbegin; + const char *dataspaceblockend; + const char *datablockbegin; + const char *datablockend; + const char *softlinkblockbegin; + const char *softlinkblockend; + const char *strblockbegin; + const char *strblockend; + const char *enumblockbegin; + const char *enumblockend; + const char *structblockbegin; + const char *structblockend; + const char *vlenblockbegin; + const char *vlenblockend; + + const char *dataspacedescriptionbegin; + const char *dataspacedescriptionend; + const char *dataspacedimbegin; + const char *dataspacedimend; + +} dump_header; + +/* + * 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 foo[] = { + * { "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 = 0, + H5LS, + H5DUMP +} ProgType; + +/*struct taken from the dumper. needed in table struct*/ +typedef struct obj_t { + unsigned long objno[2]; + char objname[1024]; + int displayed; + int recorded; + int objflag; +} obj_t; + +/*struct for the tables that the find_objs function uses*/ +typedef struct table_t { + int size; + int nobjs; + 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; + char *prefix; + unsigned int threshold; /* should be 0 or 1 */ + table_t *group_table; + table_t *type_table; + table_t *dset_table; + int status; +} find_objs_t; + +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 DATASET_DATA 1 +#define ENUM_DATA 2 + +#define COL 3 + +extern int indent; /*how far in to indent the line */ +extern int nCols; /*max number of columns for outputting */ +extern FILE *rawdatastream; /*output stream for raw data */ + +extern void indentation(int); + +/* taken from h5dump.h*/ +#define BOOT_BLOCK "BOOT_BLOCK" +#define GROUPNAME "GROUP" +#define DATASET "DATASET" +#define ATTRIBUTE "ATTRIBUTE" +#define DATATYPE "DATATYPE" +#define DATASPACE "DATASPACE" +#define DATA "DATA" +#define SCALAR "SCALAR" +#define SIMPLE "SIMPLE" +#define COMPLEX "COMPLEX" +#define STORAGELAYOUT "STORAGELAYOUT" +#define COMPRESSION "COMPRESSION" +#define EXTERNAL "EXTERNAL" +#define SOFTLINK "SOFTLINK" +#define HARDLINK "HARDLINK" +#define NLINK "NLINK" +#define FILENO "FILENO" +#define OBJNO "OBJNO" +#define STRSIZE "STRSIZE" +#define STRPAD "STRPAD" +#define CSET "CSET" +#define CTYPE "CTYPE" +#define CONCATENATOR "//" +#define DATASET "DATASET" +#define OBJID "OBJECTID" +#define BEGIN "{" +#define END "}" + +/* Definitions of useful routines */ +extern void print_version(const char *progname); +extern void h5tools_init(void); +extern void h5tools_close(void); +extern void error_msg(const char *progname, const char *fmt, ...); +extern void warn_msg(const char *progname, const char *fmt, ...); + +#endif /* H5TOOLS_H__ */ diff --git a/tools/lib/h5tools_str.c b/tools/lib/h5tools_str.c new file mode 100644 index 0000000..6fd6f85 --- /dev/null +++ b/tools/lib/h5tools_str.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2001 National Center for Supercomputing Applications + * All rights reserved. + * + * Programmer: Bill Wendling + * Monday, 19. February 2001 + * + * Purpose: These are string functions for us to use and abuse. + */ +#include +#include +#include +#include +#include + +#include "h5tools.h" /*for h5dump_t structure */ +#include "h5tools_str.h" /*function prototypes */ + +/* Variable length string datatype */ +#define STR_INIT_LEN 4096 /*initial length */ + +/*------------------------------------------------------------------------- + * Function: h5tools_str_close + * + * Purpose: Closes a string by releasing it's memory and setting the size + * information to zero. + * + * Return: void + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +h5tools_str_close(h5tools_str_t *str) +{ + if (str && str->nalloc) { + free(str->s); + memset(str, 0, sizeof(h5tools_str_t)); + } +} + +/*------------------------------------------------------------------------- + * Function: h5tools_str_len + * + * Purpose: Returns the length of the string, not counting the null + * terminator. + * + * Return: Success: Length of string + * + * Failure: 0 + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +size_t +h5tools_str_len(h5tools_str_t *str) +{ + return str->len; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_str_append + * + * Purpose: Formats variable arguments according to printf() format + * string and appends the result to variable length string STR. + * + * Return: Success: Pointer to buffer containing result. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +char * +h5tools_str_append(h5tools_str_t *str/*in,out*/, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + /* Make sure we have some memory into which to print */ + if (!str->s || str->nalloc <= 0) { + str->nalloc = STR_INIT_LEN; + str->s = malloc(str->nalloc); + assert(str->s); + str->s[0] = '\0'; + str->len = 0; + } + + while (1) { + size_t avail = str->nalloc - str->len; + size_t nchars = (size_t)vsnprintf(str->s + str->len, avail, fmt, ap); + + if (nchars < avail) { + /* success */ + str->len += nchars; + break; + } + + /* Try again with twice as much space */ + str->nalloc *= 2; + str->s = realloc(str->s, str->nalloc); + assert(str->s); + } + + va_end(ap); + return str->s; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_str_reset + * + * Purpose: Reset the string to the empty value. If no memory is + * allocated yet then initialize the h5tools_str_t struct. + * + * Return: Success: Ptr to the buffer which contains a null + * character as the first element. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +char * +h5tools_str_reset(h5tools_str_t *str/*in,out*/) +{ + if (!str->s || str->nalloc <= 0) { + str->nalloc = STR_INIT_LEN; + str->s = malloc(str->nalloc); + assert(str->s); + } + + str->s[0] = '\0'; + str->len = 0; + return str->s; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_str_trunc + * + * Purpose: Truncate a string to be at most SIZE characters. + * + * Return: Success: Pointer to the string + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +char * +h5tools_str_trunc(h5tools_str_t *str/*in,out*/, size_t size) +{ + if (size < str->len) { + str->len = size; + str->s[size] = '\0'; + } + + return str->s; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_str_fmt + * + * Purpose: Reformat a string contents beginning at character START + * according to printf format FMT. FMT should contain no format + * specifiers except possibly the `%s' variety. For example, if + * the input string is `hello' and the format is "<<%s>>" then + * the output value will be "<>". + * + * Return: Success: A pointer to the resulting string. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +char * +h5tools_str_fmt(h5tools_str_t *str/*in,out*/, size_t start, const char *fmt) +{ + char _temp[1024], *temp = _temp; + + /* If the format string is simply "%s" then don't bother doing anything */ + if (!strcmp(fmt, "%s")) + return str->s; + + /* + * Save the input value if there is a `%' anywhere in FMT. Otherwise + * don't bother because we don't need a temporary copy. + */ + if (strchr(fmt, '%')) { + if (str->len - start + 1 > sizeof(_temp)) { + temp = malloc(str->len-start + 1); + assert(temp); + } + + strcpy(temp, str->s + start); + } + + /* Reset the output string and append a formatted version */ + h5tools_str_trunc(str, start); + h5tools_str_append(str, fmt, temp); + + /* Free the temp buffer if we allocated one */ + if (temp != _temp) + free(temp); + + return str->s; +} + +/*------------------------------------------------------------------------- + * Function: h5tools_prefix + * + * Purpose: Renders the line prefix value into string STR. + * + * Return: Success: Pointer to the prefix. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Thursday, July 23, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +char * +h5tools_str_prefix(h5tools_str_t *str/*in,out*/, const h5dump_t *info, + hsize_t elmtno, int ndims, hsize_t min_idx[], + hsize_t max_idx[]) +{ + hsize_t p_prod[H5S_MAX_RANK], p_idx[H5S_MAX_RANK]; + hsize_t n, i = 0; + + h5tools_str_reset(str); + + if (ndims > 0) { + /* + * Calculate the number of elements represented by a unit change in a + * certain index position. + */ + for (i = ndims - 1, p_prod[ndims - 1] = 1; i > 0; --i) + p_prod[i - 1] = (max_idx[i] - min_idx[i]) * p_prod[i]; + + /* Calculate the index values from the element number. */ + for (i = 0, n = elmtno; i < (hsize_t)ndims; i++) { + p_idx[i] = n / p_prod[i] + min_idx[i]; + n %= p_prod[i]; + } + + /* Print the index values */ + for (i = 0; i < (hsize_t)ndims; i++) { + if (i) + h5tools_str_append(str, "%s", OPT(info->idx_sep, ",")); + + h5tools_str_append(str, OPT(info->idx_n_fmt, "%lu"), + (unsigned long)p_idx[i]); + } + } else { + /* Scalar */ + h5tools_str_append(str, OPT(info->idx_n_fmt, "%lu"), (unsigned long)0); + } + + /* Add prefix and suffix to the index */ + return h5tools_str_fmt(str, 0, OPT(info->idx_fmt, "%s: ")); +} diff --git a/tools/lib/h5tools_str.h b/tools/lib/h5tools_str.h new file mode 100644 index 0000000..89c3322 --- /dev/null +++ b/tools/lib/h5tools_str.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2001 National Center for Supercomputing Applications + * All rights reserved. + * + * Programmer: Bill Wendling + * Monday, 19. February 2001 + */ +#ifndef H5TOOLS_STR_H__ +#define H5TOOLS_STR_H__ + +typedef struct h5tools_str_t { + char *s; /*allocate string */ + size_t len; /*length of actual value */ + size_t nalloc; /*allocated size of string */ +} h5tools_str_t; + +extern void h5tools_str_close(h5tools_str_t *str); +extern size_t h5tools_str_len(h5tools_str_t *str); +extern char *h5tools_str_append(h5tools_str_t *str, const char *fmt, ...); +extern char *h5tools_str_reset(h5tools_str_t *str); +extern char *h5tools_str_trunc(h5tools_str_t *str, size_t size); +extern char *h5tools_str_fmt(h5tools_str_t *str, size_t start, const char *fmt); +extern char *h5tools_str_prefix(h5tools_str_t *str, const h5dump_t *info, + hsize_t elmtno, int ndims, hsize_t min_idx[], + hsize_t max_idx[]); + +#endif /* H5TOOLS_STR_H__ */ -- cgit v0.12