diff options
Diffstat (limited to 'tools/h5tools.c')
-rw-r--r-- | tools/h5tools.c | 934 |
1 files changed, 720 insertions, 214 deletions
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; } |