diff --git a/release_docs/CHANGELOG.md b/release_docs/CHANGELOG.md index 7f5f8d27ecc..a39b38b885d 100644 --- a/release_docs/CHANGELOG.md +++ b/release_docs/CHANGELOG.md @@ -87,6 +87,14 @@ We would like to thank the many HDF5 community members who contributed to this r ## Tools +### Fixed an issue with quoting of data values in h5ls and h5dump when displaying as ASCII characters + + When using the `-s` (h5ls) or `-r` (h5dump) option to display 1-byte integer datasets and + attributes as ASCII characters, a closing double-quote character for data values was dropped + in some cases. This double-quote character has been restored and similar formatting issues + have been fixed for cases where elements wrap to new lines according to the particular tool's + column limit setting. + ## Performance ## Fortran API diff --git a/tools/lib/h5tools_dump.c b/tools/lib/h5tools_dump.c index 34c3c0639af..df5d76eb943 100644 --- a/tools/lib/h5tools_dump.c +++ b/tools/lib/h5tools_dump.c @@ -4518,19 +4518,6 @@ h5tools_dump_data(FILE *stream, const h5tool_format_t *info, h5tools_context_t * status = h5tools_dump_mem(stream, &string_dataformat, &datactx, obj_id); } } - if (datactx.display_char && H5Tget_size(f_type) == 1 && H5Tget_class(f_type) == H5T_INTEGER) { - H5TOOLS_DEBUG("Print 1-byte integer data as an ASCII character string eol=%s", - string_dataformat.line_suf); - datactx.need_prefix = false; - string_dataformat.arr_linebreak = 0; - string_dataformat.idx_fmt = ""; - string_dataformat.line_multi_new = 0; - string_dataformat.line_suf = ""; - h5tools_str_reset(&buffer); - h5tools_str_append(&buffer, "\""); - h5tools_render_element(stream, &string_dataformat, &datactx, &buffer, &curr_pos, (size_t)ncols, - (hsize_t)0, (hsize_t)0); - } H5TOOLS_DEBUG("Print all the values Complete"); if (status == FAIL) { @@ -4540,10 +4527,18 @@ h5tools_dump_data(FILE *stream, const h5tool_format_t *info, h5tools_context_t * } done: H5Sclose(space); - H5Tclose(f_type); ctx->need_prefix = true; - h5tools_simple_prefix(stream, &outputformat, ctx, (hsize_t)0, 0); + if ((datactx.display_char && H5Tget_size(f_type) == 1) && (H5Tget_class(f_type) == H5T_INTEGER)) { + string_dataformat.arr_linebreak = 0; + string_dataformat.idx_fmt = ""; + string_dataformat.line_multi_new = 0; + h5tools_simple_prefix(stream, &string_dataformat, ctx, (hsize_t)0, 0); + } + else + h5tools_simple_prefix(stream, &outputformat, ctx, (hsize_t)0, 0); + + H5Tclose(f_type); h5tools_str_reset(&buffer); if (strlen(h5tools_dump_header_format->datablockend)) { diff --git a/tools/src/h5ls/h5ls.c b/tools/src/h5ls/h5ls.c index bd85b36db36..1d51c27387f 100644 --- a/tools/src/h5ls/h5ls.c +++ b/tools/src/h5ls/h5ls.c @@ -1547,6 +1547,21 @@ dump_dataset_values(hid_t dset) h5tools_render_element(rawoutstream, info, &ctx, &buffer, &curr_pos, (size_t)info->line_ncols, (hsize_t)0, (hsize_t)0); } + + /* Output closing line suffix character when printing 1-byte integer data as ASCII */ + if (info->ascii) { + h5tools_str_reset(&buffer); + h5tools_str_append(&buffer, "%s", outputformat.line_suf); + ctx.need_prefix = false; + info->arr_linebreak = 0; + info->line_multi_new = 0; + info->line_per_line = 0; + info->line_suf = ""; + + /* Temporarily override ncols so h5tools_render_element() doesn't try to break the line */ + h5tools_render_element(rawoutstream, info, &ctx, &buffer, &curr_pos, (size_t)ctx.cur_column + 1, + (hsize_t)0, (hsize_t)0); + } } done: H5Sclose(space); @@ -1734,6 +1749,21 @@ dump_attribute_values(hid_t attr) h5tools_render_element(rawoutstream, info, &ctx, &buffer, &curr_pos, (size_t)info->line_ncols, (hsize_t)0, (hsize_t)0); } + + /* Output closing line suffix character when printing 1-byte integer data as ASCII */ + if (info->ascii) { + h5tools_str_reset(&buffer); + h5tools_str_append(&buffer, "%s", outputformat.line_suf); + ctx.need_prefix = false; + info->arr_linebreak = 0; + info->line_multi_new = 0; + info->line_per_line = 0; + info->line_suf = ""; + + /* Temporarily override ncols so h5tools_render_element() doesn't try to break the line */ + h5tools_render_element(rawoutstream, info, &ctx, &buffer, &curr_pos, (size_t)ctx.cur_column + 1, + (hsize_t)0, (hsize_t)0); + } ctx.indent_level--; H5TOOLS_DEBUG("Attribute data read complete"); } diff --git a/tools/test/h5dump/CMakeTests.cmake b/tools/test/h5dump/CMakeTests.cmake index b1cb05b2fe9..32f3a171f1a 100644 --- a/tools/test/h5dump/CMakeTests.cmake +++ b/tools/test/h5dump/CMakeTests.cmake @@ -141,6 +141,7 @@ set (HDF5_REFERENCE_FILES tindicessub3.ddl tindicessub4.ddl tindicesyes.ddl + tintascii.ddl tints4dims.ddl tints4dimsBlock2.ddl tints4dimsBlockEq.ddl @@ -329,6 +330,7 @@ set (HDF5_REFERENCE_TEST_FILES tgrpnullspace.h5 thlink.h5 thyperslab.h5 + tintascii.h5 tints4dims.h5 tintsattrs.h5 tintsnodata.h5 @@ -1159,6 +1161,7 @@ ADD_H5_TEST (tints4dimsBlockEq RESULT_CODE 0 --enable-error-stack -d FourDimInts # test printing characters in ASCII instead of decimal ADD_H5_TEST (tchar1 RESULT_CODE 0 --enable-error-stack -r TARGET_FILE tchar.h5) +ADD_H5_TEST (tintascii RESULT_CODE 0 --enable-error-stack -r TARGET_FILE tintascii.h5) # test datatypes in ASCII and UTF8 ADD_H5_TEST (charsets RESULT_CODE 0 --enable-error-stack TARGET_FILE charsets.h5) diff --git a/tools/test/h5dump/expected/tintascii.ddl b/tools/test/h5dump/expected/tintascii.ddl new file mode 100644 index 00000000000..15f68a9e8d3 --- /dev/null +++ b/tools/test/h5dump/expected/tintascii.ddl @@ -0,0 +1,20 @@ +HDF5 "tintascii.h5" { +GROUP "/" { + DATASET "dset" { + DATATYPE H5T_STD_I8LE + DATASPACE SIMPLE { ( 81 ) / ( 81 ) } + DATA { + "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123" + "45678901234567\000" + } + ATTRIBUTE "attr" { + DATATYPE H5T_STD_I8LE + DATASPACE SIMPLE { ( 81 ) / ( 81 ) } + DATA { + "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0" + "12345678901234567\000" + } + } + } +} +} diff --git a/tools/test/h5dump/h5dumpgentest.c b/tools/test/h5dump/h5dumpgentest.c index c3d149173c7..3118fd63695 100644 --- a/tools/test/h5dump/h5dumpgentest.c +++ b/tools/test/h5dump/h5dumpgentest.c @@ -136,6 +136,8 @@ #define FILE111 "tfloat6.h5" #define FILE112 "tfloat4.h5" +#define FILE113 "tintascii.h5" + #define ONION_TEST_FIXNAME_SIZE 1024 #define ONION_TEST_PAGE_SIZE (uint32_t)32 #define ONE_DIM_SIZE 16 @@ -15179,3 +15181,37 @@ error: } H5E_END_TRY; } + +void +gent_tintascii(void) +{ + hsize_t dims[] = {81}; /* Assume default 80-column width for tools */ + hid_t file_id; + hid_t dset_id; + hid_t type_id; + hid_t space_id; + hid_t attr_id; + + /* 81-byte string, including NUL terminator */ + const char *data = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz012345678901234567"; + + file_id = H5Fcreate(FILE113, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + + type_id = H5Tcopy(H5T_NATIVE_CHAR); + + space_id = H5Screate_simple(1, dims, NULL); + + dset_id = H5Dcreate2(file_id, "dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + H5Dwrite(dset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + + attr_id = H5Acreate2(dset_id, "attr", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT); + + H5Awrite(attr_id, type_id, data); + + H5Sclose(space_id); + H5Tclose(type_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Fclose(file_id); +} diff --git a/tools/test/h5dump/h5dumpgentest.h b/tools/test/h5dump/h5dumpgentest.h index d20047b9d7a..f8e75dc8c8f 100644 --- a/tools/test/h5dump/h5dumpgentest.h +++ b/tools/test/h5dump/h5dumpgentest.h @@ -132,6 +132,8 @@ void gent_float8(void); void gent_float6(void); void gent_float4(void); +void gent_tintascii(void); + void gent_trefer_attr(void); void gent_tattr4_be(void); void gent_tno_subset(void); diff --git a/tools/test/h5gentest.c b/tools/test/h5gentest.c index 3fe7b5229e6..8965efb847b 100644 --- a/tools/test/h5gentest.c +++ b/tools/test/h5gentest.c @@ -271,6 +271,8 @@ gen_h5dump_files(void) gent_float6(); gent_float4(); + gent_tintascii(); + gent_trefer_attr(); gent_tattr4_be(); gent_tno_subset(); @@ -463,6 +465,8 @@ gen_h5ls_files(void) gent_complex_be(); #endif + gent_tintascii(); + nerrors += (gent_tdset() < 0 ? 1 : 0); gent_dataset_idx(); diff --git a/tools/test/h5ls/CMakeTests.cmake b/tools/test/h5ls/CMakeTests.cmake index 5f2b18ec4a4..824b8b5ec4b 100644 --- a/tools/test/h5ls/CMakeTests.cmake +++ b/tools/test/h5ls/CMakeTests.cmake @@ -50,6 +50,7 @@ set (LIST_HDF5_TEST_FILES tgrp_comments.h5 tgrpnullspace.h5 thlink.h5 + tintascii.h5 tloop.h5 tnestedcomp.h5 tsaf.h5 @@ -118,6 +119,7 @@ set (LIST_OTHER_TEST_FILES tgrp_comments.ls thlinks-nodangle-1.ls thlink-1.ls + tintascii.ls tloop-1.ls tmultifile.ls tnestcomp-1.ls @@ -559,6 +561,9 @@ ADD_H5_TEST (tmultifile RESULT_CODE 0 -w80 thlink.h5 tslink.h5) # tests for hard links ADD_H5_TEST (thlink-1 RESULT_CODE 0 -w80 thlink.h5) +# test printing characters in ASCII instead of decimal +ADD_H5_TEST (tintascii RESULT_CODE 0 -w80 -vldrs tintascii.h5) + # tests for compound data types ADD_H5_TEST (tcomp-1 RESULT_CODE 0 -w80 -r -d tcompound.h5) diff --git a/tools/test/h5ls/expected/tintascii.ls b/tools/test/h5ls/expected/tintascii.ls new file mode 100644 index 00000000000..c4d358fff2b --- /dev/null +++ b/tools/test/h5ls/expected/tintascii.ls @@ -0,0 +1,19 @@ +Opened "tintascii.h5" with sec2 driver. +/ Group + Location: 1:48 + Links: 1 + Modified: 2026-08-03 13:21:52 CDT +/dset Dataset {81/81} + Attribute: attr {81} + Type: native signed char + Data: + "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwx" + "yz012345678901234567\000" + Location: 1:195 + Links: 1 + Modified: 2026-08-03 13:21:52 CDT + Storage: 81 logical bytes, 81 allocated bytes, 100.00% utilization + Type: native signed char + Data: + "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456" + "78901234567\000" diff --git a/tools/test/testfiles/tintascii.h5 b/tools/test/testfiles/tintascii.h5 new file mode 100644 index 00000000000..7925291f167 Binary files /dev/null and b/tools/test/testfiles/tintascii.h5 differ