diff options
-rw-r--r-- | config/conclude.in | 3 | ||||
-rwxr-xr-x | configure | 4 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | src/H5.c | 35 | ||||
-rw-r--r-- | src/H5A.c | 2 | ||||
-rw-r--r-- | src/H5D.c | 2 | ||||
-rw-r--r-- | src/H5F.c | 5 | ||||
-rw-r--r-- | src/H5G.c | 2 | ||||
-rw-r--r-- | src/H5I.c | 42 | ||||
-rw-r--r-- | src/H5Iprivate.h | 2 | ||||
-rw-r--r-- | src/H5P.c | 2 | ||||
-rw-r--r-- | src/H5R.c | 2 | ||||
-rw-r--r-- | src/H5RA.c | 2 | ||||
-rw-r--r-- | src/H5S.c | 2 | ||||
-rw-r--r-- | src/H5T.c | 133 | ||||
-rw-r--r-- | src/H5TB.c | 2 | ||||
-rw-r--r-- | src/H5config.h.in | 3 | ||||
-rw-r--r-- | src/H5private.h | 6 | ||||
-rw-r--r-- | tools/h5ls.c | 36 | ||||
-rw-r--r-- | tools/h5tools.c | 934 | ||||
-rw-r--r-- | tools/h5tools.h | 125 |
21 files changed, 1021 insertions, 325 deletions
diff --git a/config/conclude.in b/config/conclude.in index 51cf691..63bd512 100644 --- a/config/conclude.in +++ b/config/conclude.in @@ -98,7 +98,8 @@ uninstall: # mostlyclean: -$(RM) $(LIB_OBJ) $(LIB_OBJ:.lo=.o) - -$(RM) $(TEST_OBJ) $(PROG_OBJ) $(MOSTLYCLEAN) + -$(RM) $(TEST_OBJ) $(TEST_OBJ:.lo=.o) + -$(RM) $(PROG_OBJ) $(PROG_OBJ:.lo=.o) $(MOSTLYCLEAN) # Like `mostlyclean' except it also removes the final targets: things like # libraries and executables. This target doesn't remove any file that @@ -1300,7 +1300,7 @@ case "$host" in esac # Actually configure libtool. ac_aux_dir is where install-sh is found. -AR="$AR" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ $libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ @@ -4143,7 +4143,7 @@ else fi done -for ac_func in gettimeofday BSDgettimeofday difftime snprintf +for ac_func in gettimeofday BSDgettimeofday difftime snprintf vsnprintf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:4150: checking for $ac_func" >&5 diff --git a/configure.in b/configure.in index ca76701..0505781 100644 --- a/configure.in +++ b/configure.in @@ -417,7 +417,7 @@ dnl ---------------------------------------------------------------------- dnl Check for functions. dnl AC_CHECK_FUNCS(getpwuid gethostname system getrusage fork waitpid) -AC_CHECK_FUNCS(gettimeofday BSDgettimeofday difftime snprintf) +AC_CHECK_FUNCS(gettimeofday BSDgettimeofday difftime snprintf vsnprintf) AC_CHECK_FUNCS(compress2 setsysinfo longjmp signal sigaction) AC_TRY_COMPILE([#include<sys/types.h>], [off64_t n = 0;], @@ -471,6 +471,41 @@ HDsnprintf(char *buf, size_t UNUSED size, const char *fmt, ...) } #endif /* HAVE_SNPRINTF */ +#ifndef HAVE_VSNPRINTF + + +/*------------------------------------------------------------------------- + * Function: HDvsnprintf + * + * Purpose: The same as HDsnprintf() except the variable arguments are + * passed as a va_list. + * + * Note: This function is for compatibility on systems that don't have + * vsnprintf(3). It doesn't actually check for overflow like the + * real vsnprintf() would. + * + * Return: Success: Number of characters stored, not including + * the terminating null. If this value equals + * SIZE then there was not enough space in BUF + * for all the output. + * + * Failure: -1 + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +HDvsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + return vsprintf(buf, fmt, ap); +} +#endif /* HAVE_VSNPRINTF */ + + /*------------------------------------------------------------------------- * Function: HDfprintf @@ -100,7 +100,7 @@ H5A_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_ATTR))) { - H5I_clear_group(H5I_ATTR); + H5I_clear_group(H5I_ATTR, FALSE); } else { H5I_destroy_group(H5I_ATTR); interface_initialize_g = 0; @@ -126,7 +126,7 @@ H5D_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_DATASET))) { - H5I_clear_group(H5I_DATASET); + H5I_clear_group(H5I_DATASET, FALSE); } else { H5I_destroy_group(H5I_DATASET); interface_initialize_g = 0; @@ -338,7 +338,10 @@ herr_t H5F_close_all(void) { FUNC_ENTER(H5F_close_all, FAIL); - H5I_clear_group(H5I_FILE); + if (H5I_clear_group(H5I_FILE, FALSE)<0) { + HRETURN_ERROR(H5E_FILE, H5E_CLOSEERROR, FAIL, + "unable to close one or more files"); + } FUNC_LEAVE(SUCCEED); } @@ -726,7 +726,7 @@ H5G_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_GROUP))) { - H5I_clear_group(H5I_GROUP); + H5I_clear_group(H5I_GROUP, FALSE); } else { /* Empty the object type table */ for (i=0; i<H5G_ntypes_g; i++) { @@ -364,14 +364,18 @@ H5I_nmembers(H5I_type_t grp) * Wednesday, March 24, 1999 * * Modifications: + * Robb Matzke, 1999-04-27 + * If FORCE is zero then any item for which the free callback + * failed is not removed. This function returns failure if + * items could not be removed. * *------------------------------------------------------------------------- */ herr_t -H5I_clear_group(H5I_type_t grp) +H5I_clear_group(H5I_type_t grp, hbool_t force) { H5I_id_group_t *grp_ptr = NULL; /* ptr to the atomic group */ - H5I_id_info_t *cur=NULL, *next=NULL; + H5I_id_info_t *cur=NULL, *next=NULL, *prev=NULL; intn ret_value = SUCCEED; uintn i; @@ -401,26 +405,35 @@ H5I_clear_group(H5I_type_t grp) /* * Call free method for all objects in group regardless of their reference * counts. Ignore the return value from from the free method and remove - * object from group regardless. + * object from group regardless if FORCE is non-zero. */ for (i=0; i<grp_ptr->hash_size; i++) { for (cur=grp_ptr->id_list[i]; cur; cur=next) { /* Free the object regardless of reference count */ if (grp_ptr->free_func && (grp_ptr->free_func)(cur->obj_ptr)<0) { + if (force) { #if H5I_DEBUG - if (H5DEBUG(I)) { - fprintf(H5DEBUG(I), "H5I: free grp=%d obj=0x%08lx " - "failure ignored\n", (int)grp, - (unsigned long)(cur->obj_ptr)); - } + if (H5DEBUG(I)) { + fprintf(H5DEBUG(I), "H5I: free grp=%d obj=0x%08lx " + "failure ignored\n", (int)grp, + (unsigned long)(cur->obj_ptr)); + } #endif /*H5I_DEBUG*/ + /* Add ID struct to free list */ + next = cur->next; + H5I_release_id_node(cur); + } else { + if (prev) prev->next = cur; + else grp_ptr->id_list[i] = cur; + prev = cur; + } + } else { + /* Add ID struct to free list */ + next = cur->next; + H5I_release_id_node(cur); } - - /* Add ID struct to free list */ - next = cur->next; - H5I_release_id_node(cur); } - grp_ptr->id_list[i]=NULL; + if (!prev) grp_ptr->id_list[i]=NULL; } done: @@ -472,7 +485,8 @@ H5I_destroy_group(H5I_type_t grp) * free function is invoked for each atom being freed. */ if (1==grp_ptr->count) { - H5I_clear_group(grp); + H5I_clear_group(grp, TRUE); + H5E_clear(); /*don't care about errors*/ H5MM_xfree(grp_ptr->id_list); HDmemset (grp_ptr, 0, sizeof(*grp_ptr)); } else { diff --git a/src/H5Iprivate.h b/src/H5Iprivate.h index 99b6628..dbe5078 100644 --- a/src/H5Iprivate.h +++ b/src/H5Iprivate.h @@ -74,7 +74,7 @@ typedef struct { __DLL__ intn H5I_init_group(H5I_type_t grp, size_t hash_size, uintn reserved, H5I_free_t func); __DLL__ intn H5I_nmembers(H5I_type_t grp); -__DLL__ herr_t H5I_clear_group(H5I_type_t grp); +__DLL__ herr_t H5I_clear_group(H5I_type_t grp, hbool_t force); __DLL__ herr_t H5I_destroy_group(H5I_type_t grp); __DLL__ hid_t H5I_register(H5I_type_t grp, void *object); __DLL__ void *H5I_object(hid_t id); @@ -111,7 +111,7 @@ H5P_term_interface(void) } if (n) { for (i=0; i<H5P_NCLASSES; i++) { - H5I_clear_group((H5I_type_t)(H5I_TEMPLATE_0+i)); + H5I_clear_group((H5I_type_t)(H5I_TEMPLATE_0+i), FALSE); } } else { for (i=0; i<H5P_NCLASSES; i++) { @@ -94,7 +94,7 @@ H5R_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_REFERENCE))) { - H5I_clear_group(H5I_REFERENCE); + H5I_clear_group(H5I_REFERENCE, FALSE); } else { H5I_destroy_group(H5I_REFERENCE); interface_initialize_g = 0; @@ -125,7 +125,7 @@ H5RA_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_RAGGED))) { - H5I_clear_group(H5I_RAGGED); + H5I_clear_group(H5I_RAGGED, FALSE); } else { H5T_close(H5RA_meta_type_g); H5RA_meta_type_g = NULL; @@ -122,7 +122,7 @@ H5S_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_DATASPACE))) { - H5I_clear_group(H5I_DATASPACE); + H5I_clear_group(H5I_DATASPACE, FALSE); } else { #ifdef H5S_DEBUG /* @@ -1113,50 +1113,46 @@ H5T_term_interface(void) H5T_path_t *path = NULL; if (interface_initialize_g) { - if ((n=H5I_nmembers(H5I_DATATYPE))) { - H5I_clear_group(H5I_DATATYPE); - } else { - /* Unregister all conversion functions */ - for (i=0; i<H5T_g.npaths; i++) { - path = H5T_g.path[i]; - assert (path); - - if (path->func) { - H5T_print_stats(path, &nprint/*in,out*/); - path->cdata.command = H5T_CONV_FREE; - if ((path->func)(FAIL, FAIL, &(path->cdata), - 0, NULL, NULL)<0) { + /* Unregister all conversion functions */ + for (i=0; i<H5T_g.npaths; i++) { + path = H5T_g.path[i]; + assert (path); + + if (path->func) { + H5T_print_stats(path, &nprint/*in,out*/); + path->cdata.command = H5T_CONV_FREE; + if ((path->func)(FAIL, FAIL, &(path->cdata), + 0, NULL, NULL)<0) { #ifdef H5T_DEBUG - if (H5DEBUG(T)) { - fprintf (H5DEBUG(T), "H5T: conversion function " - "0x%08lx failed to free private data for " - "%s (ignored)\n", - (unsigned long)(path->func), path->name); - } -#endif - H5E_clear(); /*ignore the error*/ + if (H5DEBUG(T)) { + fprintf (H5DEBUG(T), "H5T: conversion function " + "0x%08lx failed to free private data for " + "%s (ignored)\n", + (unsigned long)(path->func), path->name); } +#endif + H5E_clear(); /*ignore the error*/ } - H5T_close (path->src); - H5T_close (path->dst); - H5MM_xfree (path); - H5T_g.path[i] = NULL; } + H5T_close (path->src); + H5T_close (path->dst); + H5MM_xfree (path); + H5T_g.path[i] = NULL; + } - /* Clear conversion tables */ - H5T_g.path = H5MM_xfree(H5T_g.path); - H5T_g.npaths = H5T_g.apaths = 0; - H5T_g.soft = H5MM_xfree(H5T_g.soft); - H5T_g.nsoft = H5T_g.asoft = 0; + /* Clear conversion tables */ + H5T_g.path = H5MM_xfree(H5T_g.path); + H5T_g.npaths = H5T_g.apaths = 0; + H5T_g.soft = H5MM_xfree(H5T_g.soft); + H5T_g.nsoft = H5T_g.asoft = 0; - /* Unlock all datatypes, then free them */ - H5I_search (H5I_DATATYPE, H5T_unlock_cb, NULL); - H5I_destroy_group(H5I_DATATYPE); + /* Unlock all datatypes, then free them */ + H5I_search (H5I_DATATYPE, H5T_unlock_cb, NULL); + H5I_destroy_group(H5I_DATATYPE); - /* Mark interface as closed */ - interface_initialize_g = 0; - n = 1; /*H5I*/ - } + /* Mark interface as closed */ + interface_initialize_g = 0; + n = 1; /*H5I*/ } return n; } @@ -4551,6 +4547,8 @@ H5T_lock (H5T_t *dt, hbool_t immutable) * Monday, December 8, 1997 * * Modifications: + * Robb Matzke, 1999-04-27 + * This function fails if the datatype state is IMMUTABLE. * *------------------------------------------------------------------------- */ @@ -4558,9 +4556,9 @@ herr_t H5T_close(H5T_t *dt) { intn i; + H5T_t *parent = dt->parent; FUNC_ENTER(H5T_close, FAIL); - assert(dt); /* @@ -4575,41 +4573,44 @@ H5T_close(H5T_t *dt) dt->state = H5T_STATE_NAMED; } - /* Close the parent */ - if (dt->parent && H5T_close(dt->parent)<0) { - HRETURN_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, - "unable to close parent data type"); - } - /* - * Don't free locked datatypes unless we are shutting down the - * interface. + * Don't free locked datatypes. */ - if (H5T_STATE_IMMUTABLE!=dt->state) { - switch (dt->type) { - case H5T_COMPOUND: - for (i=0; i<dt->u.compnd.nmembs; i++) { - H5MM_xfree(dt->u.compnd.memb[i].name); - H5T_close(dt->u.compnd.memb[i].type); - } - H5MM_xfree(dt->u.compnd.memb); - H5MM_xfree(dt); - break; + if (H5T_STATE_IMMUTABLE==dt->state) { + HRETURN_ERROR(H5E_DATATYPE, H5E_CLOSEERROR, FAIL, + "unable to close immutable datatype"); + } - case H5T_ENUM: - for (i=0; i<dt->u.enumer.nmembs; i++) { - H5MM_xfree(dt->u.enumer.name[i]); - } - H5MM_xfree(dt->u.enumer.name); - H5MM_xfree(dt->u.enumer.value); - H5MM_xfree(dt); - break; + /* Close the datatype */ + switch (dt->type) { + case H5T_COMPOUND: + for (i=0; i<dt->u.compnd.nmembs; i++) { + H5MM_xfree(dt->u.compnd.memb[i].name); + H5T_close(dt->u.compnd.memb[i].type); + } + H5MM_xfree(dt->u.compnd.memb); + H5MM_xfree(dt); + break; - default: - H5MM_xfree(dt); + case H5T_ENUM: + for (i=0; i<dt->u.enumer.nmembs; i++) { + H5MM_xfree(dt->u.enumer.name[i]); } + H5MM_xfree(dt->u.enumer.name); + H5MM_xfree(dt->u.enumer.value); + H5MM_xfree(dt); + break; + + default: + H5MM_xfree(dt); } + /* Close the parent */ + if (parent && H5T_close(parent)<0) { + HRETURN_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, + "unable to close parent data type"); + } + FUNC_LEAVE(SUCCEED); } @@ -117,7 +117,7 @@ H5TB_term_interface(void) if (interface_initialize_g) { if ((n=H5I_nmembers(H5I_TEMPBUF))) { - H5I_clear_group(H5I_TEMPBUF); + H5I_clear_group(H5I_TEMPBUF, FALSE); } else { /* Free group and buffers */ H5I_destroy_group(H5I_TEMPBUF); diff --git a/src/H5config.h.in b/src/H5config.h.in index 0b8340e..cdb3fb2 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -194,6 +194,9 @@ /* Define if you have the system function. */ #undef HAVE_SYSTEM +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + /* Define if you have the waitpid function. */ #undef HAVE_WAITPID diff --git a/src/H5private.h b/src/H5private.h index 539e93c..6c80e2b 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -689,6 +689,9 @@ __DLL__ int64_t HDstrtoll (const char *s, const char **rest, int base); #define HDvfprintf(F,FMT,A) vfprintf(F,FMT,A) #define HDvprintf(FMT,A) vprintf(FMT,A) #define HDvsprintf(S,FMT,A) vsprintf(S,FMT,A) +#ifdef HAVE_VSNPRINTF +# define HDvsnprintf(S,N,FMT,A) vsnprintf(S,N,FMT,A) +#endif #define HDwait(W) wait(W) #define HDwaitpid(P,W,O) waitpid(P,W,O) #define HDwcstombs(S,P,Z) wcstombs(S,P,Z) @@ -704,6 +707,9 @@ char *strdup(const char *s); #ifndef HAVE_SNPRINTF __DLL__ int HDsnprintf(char *buf, size_t size, const char *fmt, ...); #endif +#ifndef HAVE_VSNPRINTF +__DLL__ int HDvsnprintf(char *buf, size_t size, const char *fmt, va_list ap); +#endif /* * These macros check whether debugging has been requested for a certain diff --git a/tools/h5ls.c b/tools/h5ls.c index 1648620..6073738 100644 --- a/tools/h5ls.c +++ b/tools/h5ls.c @@ -983,8 +983,9 @@ dump_dataset_values(hid_t dset) /* Set to all default values and then override */ memset(&info, 0, sizeof info); - info.idx_fmt = " (%s) "; + info.idx_fmt = "(%s)"; info.line_ncols = width_g; + info.line_multi_new = 1; if (label_g) info.cmpd_name = "%s="; /* @@ -996,10 +997,16 @@ dump_dataset_values(hid_t dset) info.ascii = TRUE; info.elmt_suf1 = ""; info.elmt_suf2 = ""; - info.idx_fmt = " (%s) \""; + info.line_pre =" %s \""; info.line_suf = "\""; } + /* + * If a compound datatype is split across multiple lines then add an + * ellipsis to the beginning of the continuation line. + */ + info.line_pre = " %s "; + info.line_cont = " %s "; /* * Print all the values. @@ -1066,10 +1073,17 @@ list_attr (hid_t obj, const char *attr_name, void UNUSED *op_data) /* Data */ memset(&info, 0, sizeof info); + info.line_multi_new = 1; if (nelmts<5) { - info.idx_fmt = " Data: "; + info.idx_fmt = ""; + info.line_1st = " Data: "; + info.line_pre = " "; + info.line_cont = " "; + } else { - info.idx_fmt = " (%s) "; + info.idx_fmt = "(%s)"; + info.line_pre = " %s "; + info.line_cont = " %s "; } info.line_ncols = width_g; if (label_g) info.cmpd_name = "%s="; @@ -1078,7 +1092,8 @@ list_attr (hid_t obj, const char *attr_name, void UNUSED *op_data) info.ascii = TRUE; info.elmt_suf1 = ""; info.elmt_suf2 = ""; - info.idx_fmt = " (%s) \""; + info.idx_fmt = "(%s)"; + info.line_pre = " %s \""; info.line_suf = "\""; } if ((p_type=h5dump_fixtype(type))>=0) { @@ -1191,6 +1206,7 @@ dataset_list2(hid_t dset, const char UNUSED *name) hsize_t chsize[64]; /*chunk size in elements */ int ndims; /*dimensionality */ int n, max_len; /*max extern file name length */ + double utilization; /*percent utilization of storage*/ int i; if (verbose_g>0) { @@ -1218,6 +1234,16 @@ dataset_list2(hid_t dset, const char UNUSED *name) (unsigned long)used, 1==used?"":"s", (unsigned long)total, 1==total?"":"s"); if (total>0) { +#ifdef WIN32 + hsize_t mask = (hsize_1)1 << (8*sizeof(hsize_t)-1); + if ((used & mask) || (total & mask)) { + total = 0; /*prevent utilization printing*/ + } else { + utilization = (hssize_t)used*100.0 /(hssize_t)total; + } +#else + utilization = (used*100.0)/total; +#endif printf(", %1.2f%% utilization", (used*100.0)/total); } putchar('\n'); diff --git a/tools/h5tools.c b/tools/h5tools.c index 1067494..9b5dab5 100644 --- a/tools/h5tools.c +++ b/tools/h5tools.c @@ -16,6 +16,21 @@ #include <stdlib.h> #include <string.h> #include <H5private.h> + +/* + * 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 @@ -30,30 +45,267 @@ #define OPT(X,S) ((X)?(X):(S)) #define ALIGN(A,Z) ((((A)+(Z)-1)/(Z))*(Z)) +#define START_OF_DATA 0x0001 +#define END_OF_DATA 0x0002 + +/* Variable length string datatype */ +#define STR_INIT_LEN 4096 /*initial length */ +typedef struct h5dump_str_t { + char *s; /*allocate string */ + size_t len; /*length of actual value */ + size_t nalloc; /*allocated size of string */ +} h5dump_str_t; + +/* Special strings embedded in the output */ +#define OPTIONAL_LINE_BREAK "\001" +/* Output variables */ +typedef struct h5dump_context_t { + size_t cur_column; /*current column for output */ + 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 */ +} h5dump_context_t; + /*------------------------------------------------------------------------- - * Function: h5dump_prefix + * Function: h5dump_str_close * - * Purpose: Prints the prefix to show up at the begining of the line. + * Purpose: Closes a string by releasing it's memory and setting the size + * information to zero. * * Return: void * * Programmer: Robb Matzke - * Thursday, July 23, 1998 + * Monday, April 26, 1999 * * Modifications: * *------------------------------------------------------------------------- */ static void -h5dump_prefix(char *s/*out*/, const h5dump_t *info, hsize_t elmtno, int ndims, - hsize_t min_idx[], hsize_t max_idx[]) +h5dump_str_close(h5dump_str_t *str) +{ + if (str && str->nalloc) { + free(str->s); + memset(str, 0, sizeof(h5dump_str_t)); + } +} + + +/*------------------------------------------------------------------------- + * Function: h5dump_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: + * + *------------------------------------------------------------------------- + */ +static size_t +h5dump_str_len(h5dump_str_t *str) +{ + return str->len; +} + + +/*------------------------------------------------------------------------- + * Function: h5dump_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: + * + *------------------------------------------------------------------------- + */ +static char * +h5dump_str_append(h5dump_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 = HDvsnprintf(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: h5dump_str_reset + * + * Purpose: Reset the string to the empty value. If no memory is + * allocated yet then initialize the h5dump_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: + * + *------------------------------------------------------------------------- + */ +static char * +h5dump_str_reset(h5dump_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: h5dump_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: + * + *------------------------------------------------------------------------- + */ +static char * +h5dump_str_trunc(h5dump_str_t *str/*in,out*/, size_t size) +{ + if (size<str->len) { + str->len = size; + str->s[size] = '\0'; + } + return str->s; +} + + +/*------------------------------------------------------------------------- + * Function: h5dump_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 "<<hello>>". + * + * Return: Success: A pointer to the resulting string. + * + * Failure: NULL + * + * Programmer: Robb Matzke + * Monday, April 26, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static char * +h5dump_str_fmt(h5dump_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 */ + h5dump_str_trunc(str, start); + h5dump_str_append(str, fmt, temp); + + /* Free the temp buffer if we allocated one */ + if (temp != _temp) free(temp); + return str->s; +} + + +/*------------------------------------------------------------------------- + * Function: h5dump_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: + * + *------------------------------------------------------------------------- + */ +static char * +h5dump_prefix(h5dump_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; - char temp[1024]; + h5dump_str_reset(str); if (ndims>0) { /* * Calculate the number of elements represented by a unit change in a @@ -74,92 +326,179 @@ h5dump_prefix(char *s/*out*/, const h5dump_t *info, hsize_t elmtno, int ndims, /* * Print the index values. */ - *temp = '\0'; for (i=0; i<(hsize_t)ndims; i++) { - if (i) strcat(temp, OPT(info->idx_sep, ",")); - sprintf(temp+strlen(temp), OPT(info->idx_n_fmt, "%lu"), - (unsigned long)p_idx[i]); + if (i) h5dump_str_append(str, "%s", OPT(info->idx_sep, ",")); + h5dump_str_append(str, OPT(info->idx_n_fmt, "%lu"), + (unsigned long)p_idx[i]); } } else { /* Scalar */ - sprintf(temp, OPT(info->idx_n_fmt, "%lu"), (unsigned long)0); + h5dump_str_append(str, OPT(info->idx_n_fmt, "%lu"), (unsigned long)0); } /* * Add prefix and suffix to the index. */ - sprintf(s, OPT(info->idx_fmt, "%s: "), temp); + return h5dump_str_fmt(str, 0, OPT(info->idx_fmt, "%s: ")); +} + + +/*------------------------------------------------------------------------- + * Function: h5dump_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 * +h5dump_escape(char *s/*in,out*/, size_t size, int escape_spaces) +{ + size_t n = strlen(s); + size_t i; + 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(*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) return NULL; /*would overflow*/ + 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: h5dump_sprint * - * Purpose: Prints the value pointed to by VP into the string S assuming - * the data type of VP is TYPE. + * Purpose: Renders the value pointed to by VP of type TYPE into variable + * length string STR. * - * Return: void + * 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. * *------------------------------------------------------------------------- */ -static void -h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp) +static char * +h5dump_sprint(h5dump_str_t *str/*in,out*/, const h5dump_t *info, + hid_t type, void *vp) { - size_t i, n, offset, size, dims[H5S_MAX_RANK], nelmts; -#ifndef NDEBUG - unsigned overflow = 0xaaaaaaaa; -#endif - char temp[8192]; + size_t i, n, offset, size, dims[H5S_MAX_RANK], nelmts, start; char *name, quote='\0'; hid_t memb; int nmembs, j, k, ndims; const int repeat_threshold = 8; - + static char fmt_llong[8], fmt_ullong[8]; + + /* 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 = h5dump_str_len(str); if (H5Tequal(type, H5T_NATIVE_DOUBLE)) { - sprintf(temp, "%g", *((double*)vp)); + h5dump_str_append(str, OPT(info->fmt_double, "%g"), *((double*)vp)); } else if (H5Tequal(type, H5T_NATIVE_FLOAT)) { - sprintf(temp, "%g", *((float*)vp)); + h5dump_str_append(str, OPT(info->fmt_double, "%g"), *((float*)vp)); } else if (info->ascii && (H5Tequal(type, H5T_NATIVE_SCHAR) || H5Tequal(type, H5T_NATIVE_UCHAR))) { switch (*((char*)vp)) { case '"': - strcpy(temp, "\\\""); + h5dump_str_append(str, "\\\""); break; case '\\': - strcpy(temp, "\\\\"); + h5dump_str_append(str, "\\\\"); break; case '\b': - strcpy(temp, "\\b"); + h5dump_str_append(str, "\\b"); break; case '\f': - strcpy(temp, "\\f"); + h5dump_str_append(str, "\\f"); break; case '\n': - strcpy(temp, "\\n"); + h5dump_str_append(str, "\\n"); break; case '\r': - strcpy(temp, "\\r"); + h5dump_str_append(str, "\\r"); break; case '\t': - strcpy(temp, "\\t"); + h5dump_str_append(str, "\\t"); break; default: - if (isprint(*((char*)vp))) sprintf(temp, "%c", *((char*)vp)); - else sprintf(temp, "\\%03o", *((unsigned char*)vp)); + if (isprint(*((char*)vp))) { + h5dump_str_append(str, "%c", *((char*)vp)); + } else { + h5dump_str_append(str, "\\%03o", *((unsigned char*)vp)); + } break; } } else if (H5T_STRING==H5Tget_class(type)) { size = H5Tget_size(type); - temp[0] = '\0'; quote = '\0'; for (i=0; i<size; i++) { @@ -175,115 +514,134 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp) * repeated is in it's own quote. */ if (j>repeat_threshold) { - if (quote) sprintf(temp+strlen(temp), "%c", quote); + if (quote) h5dump_str_append(str, "%c", quote); quote = '\''; - sprintf(temp+strlen(temp), "%s%c", i?" ":"", quote); + h5dump_str_append(str, "%s%c", i?" ":"", quote); } else if (!quote) { quote = '"'; - sprintf(temp+strlen(temp), "%s%c", i?" ":"", quote); + h5dump_str_append(str, "%s%c", i?" ":"", quote); } /* Print the character */ switch (((char*)vp)[i]) { case '"': - strcat(temp, "\\\""); + h5dump_str_append(str, "\\\""); break; case '\\': - strcat(temp, "\\\\"); + h5dump_str_append(str, "\\\\"); break; case '\b': - strcat(temp, "\\b"); + h5dump_str_append(str, "\\b"); break; case '\f': - strcat(temp, "\\f"); + h5dump_str_append(str, "\\f"); break; case '\n': - strcat(temp, "\\n"); + h5dump_str_append(str, "\\n"); break; case '\r': - strcat(temp, "\\r"); + h5dump_str_append(str, "\\r"); break; case '\t': - strcat(temp, "\\t"); + h5dump_str_append(str, "\\t"); break; default: if (isprint(((char*)vp)[i])) { - sprintf(temp+strlen(temp), "%c", ((char*)vp)[i]); + h5dump_str_append(str, "%c", ((char*)vp)[i]); } else { - sprintf(temp+strlen(temp), "\\%03o", - ((unsigned char*)vp)[i]); + h5dump_str_append(str, "\\%03o", ((unsigned char*)vp)[i]); } break; } /* Print the repeat count */ if (j>repeat_threshold) { - sprintf(temp+strlen(temp), "%c repeats %d times", quote, j-1); +#ifdef REPEAT_VERBOSE + h5dump_str_append(str, "%c repeats %d times", quote, j-1); +#else + h5dump_str_append(str, "%c*%d", quote, j-1); +#endif quote = '\0'; i += j-1; } } - if (quote) sprintf(temp+strlen(temp), "%c", quote); + if (quote) h5dump_str_append(str, "%c", quote); + + } else if (H5Tequal(type, H5T_NATIVE_INT)) { + h5dump_str_append(str, OPT(info->fmt_int, "%d"), + *((int*)vp)); + + } else if (H5Tequal(type, H5T_NATIVE_UINT)) { + h5dump_str_append(str, OPT(info->fmt_uint, "%u"), + *((unsigned*)vp)); } else if (H5Tequal(type, H5T_NATIVE_SCHAR)) { - sprintf(temp, "%d", *((signed char*)vp)); + h5dump_str_append(str, OPT(info->fmt_schar, "%d"), + *((signed char*)vp)); } else if (H5Tequal(type, H5T_NATIVE_UCHAR)) { - sprintf(temp, "%u", *((unsigned char*)vp)); + h5dump_str_append(str, OPT(info->fmt_uchar, "%u"), + *((unsigned char*)vp)); } else if (H5Tequal(type, H5T_NATIVE_SHORT)) { - sprintf(temp, "%d", *((short*)vp)); + h5dump_str_append(str, OPT(info->fmt_short, "%d"), + *((short*)vp)); } else if (H5Tequal(type, H5T_NATIVE_USHORT)) { - sprintf(temp, "%u", *((unsigned short*)vp)); - - } else if (H5Tequal(type, H5T_NATIVE_INT)) { - sprintf(temp, "%d", *((int*)vp)); - - } else if (H5Tequal(type, H5T_NATIVE_UINT)) { - sprintf(temp, "%u", *((unsigned*)vp)); + h5dump_str_append(str, OPT(info->fmt_ushort, "%u"), + *((unsigned short*)vp)); } else if (H5Tequal(type, H5T_NATIVE_LONG)) { - sprintf(temp, "%ld", *((long*)vp)); + h5dump_str_append(str, OPT(info->fmt_long, "%ld"), + *((long*)vp)); } else if (H5Tequal(type, H5T_NATIVE_ULONG)) { - sprintf(temp, "%lu", *((unsigned long*)vp)); + h5dump_str_append(str, OPT(info->fmt_ulong, "%lu"), + *((unsigned long*)vp)); + + } else if (H5Tequal(type, H5T_NATIVE_LLONG)) { + h5dump_str_append(str, OPT(info->fmt_llong, fmt_llong), + *((long_long*)vp)); + + } else if (H5Tequal(type, H5T_NATIVE_ULLONG)) { + h5dump_str_append(str, OPT(info->fmt_ullong, fmt_ullong), + *((unsigned long_long*)vp)); } else if (H5Tequal(type, H5T_NATIVE_HSSIZE)) { if (sizeof(hssize_t)==sizeof(int)) { - sprintf(temp, "%d", *((int*)vp)); + h5dump_str_append(str, OPT(info->fmt_int, "%d"), + *((int*)vp)); } else if (sizeof(hssize_t)==sizeof(long)) { - sprintf(temp, "%ld", *((long*)vp)); + h5dump_str_append(str, OPT(info->fmt_long, "%ld"), + *((long*)vp)); } else { - char fmt[8]; - strcpy(fmt, "%"); - strcat(fmt, PRINTF_LL_WIDTH); - strcat(fmt, "d"); - sprintf(temp, fmt, *((int64_t*)vp)); + h5dump_str_append(str, OPT(info->fmt_llong, fmt_llong), + *((int64_t*)vp)); } } else if (H5Tequal(type, H5T_NATIVE_HSIZE)) { if (sizeof(hsize_t)==sizeof(int)) { - sprintf(temp, "%u", *((unsigned*)vp)); + h5dump_str_append(str, OPT(info->fmt_uint, "%u"), + *((unsigned*)vp)); } else if (sizeof(hsize_t)==sizeof(long)) { - sprintf(temp, "%lu", *((unsigned long*)vp)); + h5dump_str_append(str, OPT(info->fmt_ulong, "%lu"), + *((unsigned long*)vp)); } else { - char fmt[8]; - strcpy(fmt, "%"); - strcat(fmt, PRINTF_LL_WIDTH); - strcat(fmt, "u"); - sprintf(temp, fmt, *((uint64_t*)vp)); + h5dump_str_append(str, OPT(info->fmt_ullong, fmt_ullong), + *((uint64_t*)vp)); } } else if (H5T_COMPOUND==H5Tget_class(type)) { nmembs = H5Tget_nmembers(type); - strcpy(temp, OPT(info->cmpd_pre, "{")); + h5dump_str_append(str, "%s", OPT(info->cmpd_pre, "{")); for (j=0; j<nmembs; j++) { - if (j) strcat(temp, OPT(info->cmpd_sep, ",")); + if (j) h5dump_str_append(str, "%s", + OPT(info->cmpd_sep, + ", " OPTIONAL_LINE_BREAK)); /* The name */ name = H5Tget_member_name(type, j); - sprintf(temp+strlen(temp), OPT(info->cmpd_name, ""), name); + h5dump_str_append(str, OPT(info->cmpd_name, ""), name); free(name); /* The value */ @@ -294,45 +652,264 @@ h5dump_sprint(char *s/*out*/, const h5dump_t *info, hid_t type, void *vp) assert(ndims>=0 && ndims<=H5S_MAX_RANK); for (k=0, nelmts=1; k<ndims; k++) nelmts *= dims[k]; - if (nelmts>1) strcat(temp, OPT(info->arr_pre, "[")); + if (nelmts>1) { + h5dump_str_append(str, "%s", OPT(info->arr_pre, "[")); + } for (i=0; i<nelmts; i++) { - if (i) strcat(temp, OPT(info->arr_sep, ",")); - h5dump_sprint(temp+strlen(temp), info, memb, - (char*)vp+offset+i*size); + if (i) { + h5dump_str_append(str, "%s", + OPT(info->arr_sep, + "," OPTIONAL_LINE_BREAK)); + } + h5dump_sprint(str, info, memb, (char*)vp+offset+i*size); + } + if (nelmts>1) { + h5dump_str_append(str, "%s", OPT(info->arr_suf, "]")); } - if (nelmts>1) strcat(temp, OPT(info->arr_suf, "]")); H5Tclose(memb); } - strcat(temp, OPT(info->cmpd_suf, "}")); + h5dump_str_append(str, "%s", OPT(info->cmpd_suf, "}")); } else if (H5T_ENUM==H5Tget_class(type)) { - if (H5Tenum_nameof(type, vp, temp, sizeof temp)<0) { - strcpy(temp, "0x"); + char enum_name[1024]; + if (H5Tenum_nameof(type, vp, enum_name, sizeof enum_name)>=0) { + h5dump_escape(enum_name, sizeof enum_name, TRUE); + } else { + h5dump_str_append(str, "0x"); n = H5Tget_size(type); for (i=0; i<n; i++) { - sprintf(temp+strlen(temp), "%02x", ((unsigned char*)vp)[i]); + h5dump_str_append(str, "%02x", ((unsigned char*)vp)[i]); } } } else { - strcpy(temp, "0x"); + h5dump_str_append(str, "0x"); n = H5Tget_size(type); for (i=0; i<n; i++) { - sprintf(temp+strlen(temp), "%02x", ((unsigned char*)vp)[i]); + h5dump_str_append(str, "%02x", ((unsigned char*)vp)[i]); } } - sprintf(s, OPT(info->elmt_fmt, "%s"), temp); + return h5dump_str_fmt(str, start, OPT(info->elmt_fmt, "%s")); +} - /* - * We should really fix this so it's not possible to overflow the `temp' - * buffer. - */ - assert(overflow==0xaaaaaaaa); + +/*------------------------------------------------------------------------- + * Function: h5dump_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 +h5dump_ncols(const char *s) +{ + 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: + * + *------------------------------------------------------------------------- + */ +static void +h5dump_simple_prefix(FILE *stream, const h5dump_t *info, + h5dump_context_t *ctx, hsize_t elmtno, int secnum) +{ + h5dump_str_t prefix; + + memset(&prefix, 0, sizeof(h5dump_str_t)); + if (!ctx->need_prefix) return; + + /* Terminate previous line, if any */ + if (ctx->cur_column) { + fputs(OPT(info->line_suf, ""), stream); + putc('\n', stream); + fputs(OPT(info->line_sep, ""), stream); + } + + /* Calculate new prefix */ + h5dump_prefix(&prefix, info, elmtno, ctx->ndims, + ctx->p_min_idx, ctx->p_max_idx); + + /* Write new prefix to output */ + if (0==elmtno && 0==secnum && info->line_1st) { + fputs(h5dump_str_fmt(&prefix, 0, info->line_1st), + stream); + } else if (secnum && info->line_cont) { + fputs(h5dump_str_fmt(&prefix, 0, info->line_cont), + stream); + } else { + fputs(h5dump_str_fmt(&prefix, 0, info->line_pre), + stream); + } + ctx->cur_column = ctx->prev_prefix_len = h5dump_str_len(&prefix); + ctx->need_prefix = 0; + + /* Free string */ + h5dump_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: + * + *------------------------------------------------------------------------- + */ +static void +h5dump_simple_data(FILE *stream, const h5dump_t *info, + h5dump_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 */ + h5dump_str_t buffer; /*string into which to render */ + int multiline; /*datum was multiline */ + + /* Setup */ + memset(&buffer, 0, sizeof(h5dump_str_t)); + size = H5Tget_size(type); + if (info->line_ncols>0) ncols = info->line_ncols; + h5dump_simple_prefix(stream, info, ctx, 0, 0); + + for (i=0; i<nelmts; i++) { + + /* Render the element */ + h5dump_str_reset(&buffer); + h5dump_sprint(&buffer, info, type, mem+i*size); + if (i+1<nelmts || 0==(flags & END_OF_DATA)) { + h5dump_str_append(&buffer, "%s", OPT(info->elmt_suf1, ",")); + } + s = h5dump_str_fmt(&buffer, 0, "%s"); + + /* + * If the element would split on multiple lines if printed at our + * current location... + */ + if (1==info->line_multi_new && + (ctx->cur_column + h5dump_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 + h5dump_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; + } + } + + /* + * 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 (1==info->line_multi_new && + ctx->prev_multiline && + (ctx->cur_column + h5dump_ncols(s) + + strlen(OPT(info->elmt_suf2, " ")) + + strlen(OPT(info->line_suf, ""))) > ncols) { + 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. + */ + if ((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 && 0==secnum) { + 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; + } + h5dump_str_close(&buffer); +} + + + +/*------------------------------------------------------------------------- * Function: h5dump_simple_dset * * Purpose: Print some values from a dataset with a simple data space. @@ -354,21 +931,15 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, hid_t p_type) { hid_t f_space; /*file data space */ - int ndims; /*dimensionality */ hsize_t elmtno, i; /*counters */ int carry; /*counter carry value */ hssize_t zero[8]; /*vector of zeros */ - int need_prefix=1; /*indices need printing */ + unsigned flags; /*buffer extent flags */ /* Print info */ - hsize_t p_min_idx[H5S_MAX_RANK];/*min selected index */ - hsize_t p_max_idx[H5S_MAX_RANK];/*max selected index */ + h5dump_context_t ctx; /*print context */ size_t p_type_nbytes; /*size of memory type */ hsize_t p_nelmts; /*total selected elmts */ - char p_buf[8192]; /*output string */ - size_t p_column=0; /*output column */ - size_t p_ncolumns=80; /*default num columns */ - char p_prefix[1024]; /*line prefix string */ /* Stripmine info */ hsize_t sm_size[H5S_MAX_RANK]; /*stripmine size */ @@ -382,20 +953,24 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, hsize_t hs_size[H5S_MAX_RANK]; /*size this pass */ hsize_t hs_nelmts; /*elements in request */ + + /* * 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.need_prefix = 1; f_space = H5Dget_space(dset); - ndims = H5Sget_simple_extent_ndims(f_space); - if ((size_t)ndims>NELMTS(sm_size)) return -1; + 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 */ - for (i=0; i<(hsize_t)ndims; i++) p_min_idx[i] = 0; - H5Sget_simple_extent_dims(f_space, p_max_idx, NULL); - for (i=0, p_nelmts=1; i<(hsize_t)ndims; i++) { - p_nelmts *= p_max_idx[i]-p_min_idx[i]; + for (i=0; i<(hsize_t)(ctx.ndims); i++) ctx.p_min_idx[i] = 0; + H5Sget_simple_extent_dims(f_space, ctx.p_max_idx, NULL); + for (i=0, p_nelmts=1; i<(hsize_t)(ctx.ndims); i++) { + p_nelmts *= ctx.p_max_idx[i]-ctx.p_min_idx[i]; } if (0==p_nelmts) return 0; /*nothing to print*/ @@ -404,8 +979,8 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, * a hyperslab whose size is manageable. */ p_type_nbytes = H5Tget_size(p_type); - for (i=ndims, sm_nbytes=p_type_nbytes; i>0; --i) { - sm_size[i-1] = MIN (p_max_idx[i-1]-p_min_idx[i-1], + for (i=ctx.ndims, sm_nbytes=p_type_nbytes; i>0; --i) { + sm_size[i-1] = MIN (ctx.p_max_idx[i-1] - ctx.p_min_idx[i-1], H5DUMP_BUFSIZE/sm_nbytes); sm_nbytes *= sm_size[i-1]; assert(sm_nbytes>0); @@ -414,18 +989,15 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, sm_nelmts = sm_nbytes/p_type_nbytes; sm_space = H5Screate_simple(1, &sm_nelmts, NULL); - /* Local things */ - if (info->line_ncols>0) p_ncolumns = info->line_ncols; - /* 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 (ndims>0) { - for (i=0, hs_nelmts=1; i<(hsize_t)ndims; i++) { - hs_size[i] = MIN(sm_size[i], p_max_idx[i]-hs_offset[i]); + if (ctx.ndims>0) { + for (i=0, hs_nelmts=1; i<(hsize_t)(ctx.ndims); i++) { + hs_size[i] = MIN(ctx.p_max_idx[i]-hs_offset[i], sm_size[i]); hs_nelmts *= hs_size[i]; } H5Sselect_hyperslab(f_space, H5S_SELECT_SET, hs_offset, NULL, @@ -442,54 +1014,26 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, if (H5Dread(dset, p_type, sm_space, f_space, H5P_DEFAULT, sm_buf)<0) { return -1; } - - /* Print the data */ - for (i=0; i<hs_nelmts; i++) { - /* Render the element */ - h5dump_sprint(p_buf, info, p_type, sm_buf+i*p_type_nbytes); - if (elmtno+i+1<p_nelmts) { - strcat(p_buf, OPT(info->elmt_suf1, ",")); - } - /* Print the prefix */ - if ((p_column + - strlen(p_buf) + - strlen(OPT(info->elmt_suf2, " ")) + - strlen(OPT(info->line_suf, ""))) > p_ncolumns) { - need_prefix = 1; - } - if (need_prefix) { - h5dump_prefix(p_prefix, info, elmtno+i, ndims, - p_min_idx, p_max_idx); - if (p_column) { - fputs(OPT(info->line_suf, ""), stream); - putc('\n', stream); - fputs(OPT(info->line_sep, ""), stream); - } - fputs(p_prefix, stream); - p_column = strlen(p_prefix); - need_prefix = 0; - } else { - fputs(OPT(info->elmt_suf2, " "), stream); - p_column += strlen(OPT(info->elmt_suf2, " ")); - } - - fputs(p_buf, stream); - p_column += strlen(p_buf); - } + /* Print the data */ + flags = ((0==elmtno?START_OF_DATA:0) | + (elmtno+hs_nelmts>=p_nelmts?END_OF_DATA:0)); + h5dump_simple_data(stream, info, &ctx, flags, hs_nelmts, p_type, + sm_buf); /* Calculate the next hyperslab offset */ - for (i=ndims, carry=1; i>0 && carry; --i) { + for (i=ctx.ndims, carry=1; i>0 && carry; --i) { hs_offset[i-1] += hs_size[i-1]; - if (hs_offset[i-1]==(hssize_t)p_max_idx[i-1]) { - hs_offset[i-1] = p_min_idx[i-1]; + if (hs_offset[i-1]==(hssize_t)(ctx.p_max_idx[i-1])) { + hs_offset[i-1] = ctx.p_min_idx[i-1]; } else { carry = 0; } } } - if (p_column) { + /* Terminate the output */ + if (ctx.cur_column) { fputs(OPT(info->line_suf, ""), stream); putc('\n', stream); fputs(OPT(info->line_sep, ""), stream); @@ -520,81 +1064,43 @@ h5dump_simple_dset(FILE *stream, const h5dump_t *info, hid_t dset, */ static int h5dump_simple_mem(FILE *stream, const h5dump_t *info, hid_t type, - hid_t space, void *_mem) + hid_t space, void *mem) { - unsigned char *mem = (unsigned char*)_mem; - int ndims; /*dimensionality */ hsize_t i; /*counters */ - int need_prefix=1; /*indices need printing */ - - /* Print info */ - hsize_t p_min_idx[H5S_MAX_RANK];/*min selected index */ - hsize_t p_max_idx[H5S_MAX_RANK];/*max selected index */ - size_t p_type_nbytes; /*size of memory type */ - hsize_t p_nelmts; /*total selected elmts */ - char p_buf[8192]; /*output string */ - size_t p_column=0; /*output column */ - size_t p_ncolumns=80; /*default num columns */ - char p_prefix[1024]; /*line prefix string */ + size_t size; /*size of each element */ + hsize_t nelmts; /*total selected elmts */ + h5dump_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. */ - ndims = H5Sget_simple_extent_ndims(space); - if ((size_t)ndims>NELMTS(p_min_idx)) return -1; + memset(&ctx, 0, sizeof ctx); + ctx.need_prefix = 1; + ctx.ndims = H5Sget_simple_extent_ndims(space); + if ((size_t)(ctx.ndims)>NELMTS(ctx.p_min_idx)) return -1; /* Assume entire data space to be printed */ - for (i=0; i<(hsize_t)ndims; i++) p_min_idx[i] = 0; - H5Sget_simple_extent_dims(space, p_max_idx, NULL); - for (i=0, p_nelmts=1; i<(hsize_t)ndims; i++) { - p_nelmts *= p_max_idx[i]-p_min_idx[i]; + 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; i<(hsize_t)(ctx.ndims); i++) { + nelmts *= ctx.p_max_idx[i] - ctx.p_min_idx[i]; } - if (0==p_nelmts) return 0; /*nothing to print*/ - p_type_nbytes = H5Tget_size(type); - - /* Local things */ - if (info->line_ncols>0) p_ncolumns = info->line_ncols; + if (0==nelmts) return 0; /*nothing to print*/ + size = H5Tget_size(type); - for (i=0; i<p_nelmts; i++) { - /* Render the element */ - h5dump_sprint(p_buf, info, type, mem+i*p_type_nbytes); - if (i+1<p_nelmts) { - strcat(p_buf, OPT(info->elmt_suf1, ",")); - } + /* Print it */ + h5dump_simple_data(stream, info, &ctx, START_OF_DATA|END_OF_DATA, + nelmts, type, mem); - /* Print the prefix */ - if ((p_column + - strlen(p_buf) + - strlen(OPT(info->elmt_suf2, " ")) + - strlen(OPT(info->line_suf, ""))) > p_ncolumns) { - need_prefix = 1; - } - if (need_prefix) { - h5dump_prefix(p_prefix, info, i, ndims, p_min_idx, p_max_idx); - if (p_column) { - fputs(OPT(info->line_suf, ""), stream); - putc('\n', stream); - fputs(OPT(info->line_sep, ""), stream); - } - fputs(p_prefix, stream); - p_column = strlen(p_prefix); - need_prefix = 0; - } else { - fputs(OPT(info->elmt_suf2, " "), stream); - p_column += strlen(OPT(info->elmt_suf2, " ")); - } - - fputs(p_buf, stream); - p_column += strlen(p_buf); - } - - if (p_column) { + /* Terminate the output */ + if (ctx.cur_column) { fputs(OPT(info->line_suf, ""), stream); putc('\n', stream); fputs(OPT(info->line_sep, ""), stream); } + return 0; } diff --git a/tools/h5tools.h b/tools/h5tools.h index 8b5cbfe..a6ed864 100644 --- a/tools/h5tools.h +++ b/tools/h5tools.h @@ -18,15 +18,84 @@ */ 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. + * + * 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. + * + * Numeric data is also subject to the formats for individual elements. + */ + 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; + + /* * 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 comma. + * value is a ",\001" ("\001" indicates an optional line + * break). * - * suf: A strint to print at the end of each array. The default + * suf: A string to print at the end of each array. The default * value is a right square bracket `]'. */ const char *arr_pre; @@ -42,7 +111,9 @@ typedef struct h5dump_t { * followed by an equal sign and then the value. * * sep: A string that separates one member from another. The - * default is a comma. + * 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. @@ -58,13 +129,6 @@ typedef struct h5dump_t { /* * Fields associated with the individual elements. * - * 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. - * * fmt: A printf(3c) format to use to print the value string * after it has been rendered. The default is "%s". * @@ -76,7 +140,6 @@ typedef struct h5dump_t { * are followed on the same line by another element. The * default is a single space. */ - int ascii; const char *elmt_fmt; const char *elmt_suf1; const char *elmt_suf2; @@ -107,6 +170,22 @@ typedef struct h5dump_t { * * ncols: Number of columns per line defaults to 80. * + * 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. @@ -114,11 +193,33 @@ typedef struct h5dump_t { * 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. */ int line_ncols; /*columns of output */ + 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? */ } h5dump_t; |