From 436d6910ec95e4f0191387931b1ca01ff29aff85 Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Fri, 13 May 2022 18:01:39 -0500 Subject: INITIAL attempt at User Guide in doxygen (#1678) * HDFFV-10865 - merge from dev, HDFArray perf fix. * Remove duplicate setting * Whitespace changes after clang format * Undo version 11 clang format changes * Merge CMake changes from develop * test testing script merge from develop * Update supported platforms * PR#3 merge from develop * Merge gcc 10 diagnostics option from develop * Merge #318 OSX changes from develop * Merge small changes from develop * Minor non-space formatting changes * #386 copyright corrections for java folder * Merges from develop #358 patches from vtk #361 fix header guard spelling * Merge updates #358 patches from vtk #361 fix header guard spelling * format fix * Fix missing underscore and make H5public.h closer to dev * Merges from develop #340 clang -Wformat-security warnings #360 Fixed uninitialized warnings header guard underscore cleanup JNI cleanup * format alignment * Add missing test ref file * Merge #380 from develop * Finish java merges from develop * Fix java issues with tests and javadoc * Correct use of attribute access plist * Remove debug code * Remove unused variable * Change file access to read only for java tests * Split clang format operations. * More javadoc comments * Remove pre-split setting * format source * Change windows TS to use older VS. * Mostly all javadoc fixes, one argument rename. * synch file * Merge of long double fix and compiler flags * HDFFV-11229 merge changes from develop * HDFFV-11229 correct test script * HDFFV-11229 update autotools test script for two ref files * HDFFV-11229 merge dev changes for long double display in tools * Committing clang-format changes * minor whitespace * remove unneeded macro * Committing clang-format changes * Add "option" command for clang options * Rework CMake add_custom to use the BYPRODUCTS argument Update pkgconfig scripts for parallel builds. Fix install COPYING file reference. Remove unused round defines. Change CMake default setting of BUILD_CPP to off. * Fortran target depends * Remove incorrect source attribute * Revert define removal * printf specifiers and VS2015 min changes * Committing clang-format changes * Add time struct * TRILAB-227 and tools debug merges from develop * Merge various changes from dev * Issue #669 remove version from pkgcfg filename * remove version from h5cc script * doxygen changes merged from develop * Committing clang-format changes * Merge CMake fortran ninja changes from dev * Enable fortran to gcc yaml * Refactor Fortran CMake config tests and CMake test args * Merge warnings files fixes from develop * Fix cmake configure path * Update missing release note info. * Update code owners * Add known problem * Use only core library for testing dynamic plugins. CMake uses H5_HAVE_DIRECT instead of DIRECT_VFD * INITIAL attempt at User Guide in doxygen * Add quick H5E to show actual UG header sections * Add Error Handling chapter * Cleanup format changes * Committing clang-format changes Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- doxygen/CMakeLists.txt | 2 +- doxygen/Doxyfile.in | 2 +- doxygen/dox/Overview.dox | 6 +- doxygen/dox/UsersGuide.dox | 145 ++++++++++ doxygen/hdf5doxy_layout.xml | 1 + doxygen/img/Shared_Attribute.jpg | Bin 0 -> 37209 bytes doxygen/img/UML_Attribute.jpg | Bin 0 -> 36134 bytes src/H5Amodule.h | 332 +++++++++++++++++++++- src/H5Emodule.h | 576 +++++++++++++++++++++++++++++++++++++-- 9 files changed, 1021 insertions(+), 43 deletions(-) create mode 100644 doxygen/dox/UsersGuide.dox create mode 100644 doxygen/img/Shared_Attribute.jpg create mode 100644 doxygen/img/UML_Attribute.jpg diff --git a/doxygen/CMakeLists.txt b/doxygen/CMakeLists.txt index 920fafa..38c2fad 100644 --- a/doxygen/CMakeLists.txt +++ b/doxygen/CMakeLists.txt @@ -21,7 +21,7 @@ if (DOXYGEN_FOUND) set (DOXYGEN_HTML_HEADER ${HDF5_DOXYGEN_DIR}/hdf5_header.html) set (DOXYGEN_HTML_FOOTER ${HDF5_DOXYGEN_DIR}/hdf5_footer.html) set (DOXYGEN_HTML_EXTRA_STYLESHEET ${HDF5_DOXYGEN_DIR}/hdf5doxy.css) - set (DOXYGEN_HTML_EXTRA_FILES "${HDF5_DOXYGEN_DIR}/hdf5_navtree_hacks.js ${HDF5_DOXYGEN_DIR}/img/FF-IH_FileGroup.gif ${HDF5_DOXYGEN_DIR}/img/FF-IH_FileObject.gif ${HDF5_DOXYGEN_DIR}/img/FileFormatSpecChunkDiagram.jpg ${HDF5_DOXYGEN_DIR}/img/ftv2node.png ${HDF5_DOXYGEN_DIR}/img/ftv2pnode.png ${HDF5_DOXYGEN_DIR}/img/HDFG-logo.png ${HDF5_DOXYGEN_DIR}/img/IOFlow2.gif ${HDF5_DOXYGEN_DIR}/img/IOFlow3.gif ${HDF5_DOXYGEN_DIR}/img/IOFlow.gif ${HDF5_DOXYGEN_DIR}/img/PaletteExample1.gif ${HDF5_DOXYGEN_DIR}/img/Palettes.fm.anc.gif") + set (DOXYGEN_HTML_EXTRA_FILES "${HDF5_DOXYGEN_DIR}/hdf5_navtree_hacks.js ${HDF5_DOXYGEN_DIR}/img/FF-IH_FileGroup.gif ${HDF5_DOXYGEN_DIR}/img/FF-IH_FileObject.gif ${HDF5_DOXYGEN_DIR}/img/FileFormatSpecChunkDiagram.jpg ${HDF5_DOXYGEN_DIR}/img/ftv2node.png ${HDF5_DOXYGEN_DIR}/img/ftv2pnode.png ${HDF5_DOXYGEN_DIR}/img/HDFG-logo.png ${HDF5_DOXYGEN_DIR}/img/IOFlow2.gif ${HDF5_DOXYGEN_DIR}/img/IOFlow3.gif ${HDF5_DOXYGEN_DIR}/img/IOFlow.gif ${HDF5_DOXYGEN_DIR}/img/PaletteExample1.gif ${HDF5_DOXYGEN_DIR}/img/Palettes.fm.anc.gif ${HDF5_DOXYGEN_DIR}/img/UML_Attribute.jpg ${HDF5_DOXYGEN_DIR}/img/Shared_Attribute.jpg") set (DOXYGEN_TAG_FILE ${HDF5_BINARY_DIR}/hdf5.tag) set (DOXYGEN_SERVER_BASED_SEARCH NO) set (DOXYGEN_EXTERNAL_SEARCH NO) diff --git a/doxygen/Doxyfile.in b/doxygen/Doxyfile.in index 7958767..e391422 100644 --- a/doxygen/Doxyfile.in +++ b/doxygen/Doxyfile.in @@ -938,7 +938,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = @HDF5_DOXYGEN_DIR@/img # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/doxygen/dox/Overview.dox b/doxygen/dox/Overview.dox index 040769c..8f428b5 100644 --- a/doxygen/dox/Overview.dox +++ b/doxygen/dox/Overview.dox @@ -23,7 +23,7 @@ documents cover a mix of tasks, concepts, and reference, to help a specific \par Versions Version-specific documentation (see the version in the title area) can be found here: - - HDF5 develop branch (this site) + - HDF5 1.10 branch (this site) - HDF5 1.12.x - HDF5 1.10.x - HDF5 1.8.x @@ -36,10 +36,6 @@ documents cover a mix of tasks, concepts, and reference, to help a specific \par Offline reading You can download it as a tgz archive for offline reading. -\par History - A snapshot (~April 2017) of the pre-Doxygen HDF5 documentation can be found - here. - \par ToDo List There is plenty of unfinished business. diff --git a/doxygen/dox/UsersGuide.dox b/doxygen/dox/UsersGuide.dox new file mode 100644 index 0000000..22fe5c6 --- /dev/null +++ b/doxygen/dox/UsersGuide.dox @@ -0,0 +1,145 @@ +/** \page UG HDF5 User’s Guide + +
+HDF5 Release 1.10 + +\image html HDFG-logo.png "The HDF Group" + +
+ +\section sec_data_model The HDF5 Data Model and File Structure + - Introduction + - The Abstract Data Model + - The HDF5 Storage Model + - The Structure of an HDF5 File + +\section sec_program The HDF5 Library and Programming Model + - Introduction + - The HDF5 Programming Model + - The Data Transfer Pipeline + +\section sec_file The HDF5 File + - Introduction + - File Access Modes + - File Creation and File Access Properties + - Low-level File Drivers + - "Programming Model for Files + - Using h5dump to View a File + - File Function Summaries + - Creating or Opening an HDF5 File + - Closing an HDF5 File + - File Property Lists + - Alternate File Storage Layouts and Low-level File Drivers + - Code Examples for Opening and Closing Files + - Working with Multiple HDF5 Files + +\section sec_group HDF5 Groups + - Introduction + - Description of the Group Object + - Using h5dump + - Group Function Summaries + - Programming Model for Groups + - Examples of File Structures + +\section sec_dataset HDF5 Datasets + - Introduction + - Dataset Function Summaries + - Programming Model for Datasets + - Data Transfer + - Allocation of Space in the File + - Using HDF5 Filters + +\section sec_datatype HDF5 Datatypes + +\section sec_dataspace HDF5 Dataspaces and Partial I/O + +\ref sec_attribute +\li \ref subsec_attribute_intro +\li \ref subsec_attribute_program + +\li \ref subsec_error_H5A +\li \ref subsec_attribute_work + +\li \ref subsec_attribute_special + +\ref sec_error +\li \ref subsec_error_intro +\li \ref subsec_error_program +\li \ref subsec_error_H5E +\li \ref subsec_error_ops + +\li \ref subsec_error_adv + + +\section sec_plist Properties and Property Lists in HDF5 + +\section sec_addition Additional Resources + + + +\par Don't like what you see? - You can help to improve this User’s Guide + Complete the survey linked near the top of this page!\n + We treat documentation like code: Fork the + HDF5 repo, make changes, and create a + pull request !\n + +*/ \ No newline at end of file diff --git a/doxygen/hdf5doxy_layout.xml b/doxygen/hdf5doxy_layout.xml index 24642b5..20e0123 100644 --- a/doxygen/hdf5doxy_layout.xml +++ b/doxygen/hdf5doxy_layout.xml @@ -5,6 +5,7 @@ + diff --git a/doxygen/img/Shared_Attribute.jpg b/doxygen/img/Shared_Attribute.jpg new file mode 100644 index 0000000..058eeec Binary files /dev/null and b/doxygen/img/Shared_Attribute.jpg differ diff --git a/doxygen/img/UML_Attribute.jpg b/doxygen/img/UML_Attribute.jpg new file mode 100644 index 0000000..5b3db7d Binary files /dev/null and b/doxygen/img/UML_Attribute.jpg differ diff --git a/src/H5Amodule.h b/src/H5Amodule.h index 9f86ddd..b973304 100644 --- a/src/H5Amodule.h +++ b/src/H5Amodule.h @@ -29,30 +29,86 @@ #define H5_MY_PKG_ERR H5E_ATTR #define H5_MY_PKG_INIT YES -/**\defgroup H5A H5A +/** \page H5A_UG HDF5 Attributes * - * Use the functions in this module to manage HDF5 attributes. + * \section sec_attribute HDF5 Attributes * - * Like HDF5 datasets, HDF5 attributes are array variables which have an element - * datatype and a shape (dataspace). However, they perform a different function: - * Attributes decorate other HDF5 objects, and are typically used to - * represent application metadata. Unlike datasets, the HDF5 library does not - * support partial I/O operations for attributes and they cannot be compressed - * or extended. + * An HDF5 attribute is a small metadata object describing the nature and/or intended usage of a primary data + * object. A primary data object may be a dataset, group, or committed datatype. + * + * \subsection subsec_attribute_intro Introduction + * + * Attributes are assumed to be very small as data objects go, so storing them as standard HDF5 datasets would + * be quite inefficient. HDF5 attributes are therefore managed through a special attributes interface, + * \ref H5A, which is designed to easily attach attributes to primary data objects as small datasets + * containing metadata information and to minimize storage requirements. + * + * Consider, as examples of the simplest case, a set of laboratory readings taken under known temperature and + * pressure conditions of 18.0 degrees Celsius and 0.5 atmospheres, respectively. The temperature and pressure + * stored as attributes of the dataset could be described as the following name/value pairs: + * \li temp=18.0 + * \li pressure=0.5 + * + * While HDF5 attributes are not standard HDF5 datasets, they have much in common: + * \li An attribute has a user-defined dataspace and the included metadata has a user-assigned datatype + * \li Metadata can be of any valid HDF5 datatype + * \li Attributes are addressed by name + * + * But there are some very important differences: + * \li There is no provision for special storage such as compression or chunking + * \li There is no partial I/O or sub-setting capability for attribute data + * \li Attributes cannot be shared + * \li Attributes cannot have attributes + * \li Being small, an attribute is stored in the object header of the object it describes and is thus + * attached directly to that object + * + * \subsection subsec_error_H5A Attribute Function Summaries + * \ref H5A reference manual + * + * \subsection subsec_attribute_program Programming Model for Attributes + * + * The figure below shows the UML model for an HDF5 attribute and its associated dataspace and datatype. + * \image html UML_Attribute.jpg "The UML model for an HDF5 attribute" + * + * Creating an attribute is similar to creating a dataset. To create an attribute, the application must + * specify the object to which the attribute is attached, the datatype and dataspace of the attribute + * data, and the attribute creation property list. + * + * The following steps are required to create and write an HDF5 attribute: + * \li Obtain the object identifier for the attribute’s primary data object + * \li Define the characteristics of the attribute and specify the attribute creation property list + *
  • Define the datatype
  • + *
  • Define the dataspace
  • + *
  • Specify the attribute creation property list
+ * \li Create the attribute + * \li Write the attribute data (optional) + * \li Close the attribute (and datatype, dataspace, and attribute creation property list, if necessary) + * \li Close the primary data object (if appropriate) + * + * The following steps are required to open and read/write an existing attribute. Since HDF5 attributes + * allow no partial I/O, you need specify only the attribute and the attribute’s memory datatype to read it: + * \li Obtain the object identifier for the attribute’s primary data object + * \li Obtain the attribute’s name or index + * \li Open the attribute + * \li Get attribute dataspace and datatype (optional) + * \li Specify the attribute’s memory type + * \li Read and/or write the attribute data + * \li Close the attribute + * \li Close the primary data object (if appropriate) * * - * + * * * * - * + * * * * *
CreateRead
CreateUpdate
* \snippet{lineno} H5A_examples.c create * - * \snippet{lineno} H5A_examples.c read + * \snippet{lineno} H5A_examples.c update *
UpdateDelete
ReadDelete
- * \snippet{lineno} H5A_examples.c update + * \snippet{lineno} H5A_examples.c read * * \snippet{lineno} H5A_examples.c delete @@ -60,6 +116,258 @@ *
* + * \subsection subsec_attribute_work Working with Attributes + * + * \subsubsection subsubsec_attribute_work_struct The Structure of an Attribute + * + * An attribute has two parts: name and value(s). + * + * HDF5 attributes are sometimes discussed as name/value pairs in the form name=value. + * + * An attribute’s name is a null-terminated ASCII or UTF-8 character string. Each attribute attached to an + * object has a unique name. + * + * The value portion of the attribute contains one or more data elements of the same datatype. + * + * HDF5 attributes have all the characteristics of HDF5 datasets except that there is no partial I/O + * capability. In other words, attributes can be written and read only in full with no sub-setting. + * + * \subsubsection subsubsec_attribute_work_create Creating, Writing, and Reading Attributes + * + * If attributes are used in an HDF5 file, these functions will be employed: \ref H5Acreate, \ref H5Awrite, + * and \ref H5Aread. \ref H5Acreate and \ref H5Awrite are used together to place the attribute in the file. If + * an attribute is to be used and is not currently in memory, \ref H5Aread generally comes into play + * usually in concert with one each of the H5Aget_* and H5Aopen_* functions. + * + * To create an attribute, call H5Acreate: + * \code + * hid_t H5Acreate (hid_t loc_id, const char *name, + * hid_t type_id, hid_t space_id, hid_t create_plist, + * hid_t access_plist) + * \endcode + * loc_id identifies the object (dataset, group, or committed datatype) to which the attribute is to be + * attached. name, type_id, space_id, and create_plist convey, respectively, the attribute’s name, datatype, + * dataspace, and attribute creation property list. The attribute’s name must be locally unique: it must be + * unique within the context of the object to which it is attached. + * + * \ref H5Acreate creates the attribute in memory. The attribute does not exist in the file until + * \ref H5Awrite writes it there. + * + * To write or read an attribute, call H5Awrite or H5Aread, respectively: + * \code + * herr_t H5Awrite (hid_t attr_id, hid_t mem_type_id, const void *buf) + * herr_t H5Aread (hid_t attr_id, hid_t mem_type_id, void *buf) + * \endcode + * attr_id identifies the attribute while mem_type_id identifies the in-memory datatype of the attribute data. + * + * \ref H5Awrite writes the attribute data from the buffer buf to the file. \ref H5Aread reads attribute data + * from the file into buf. + * + * The HDF5 Library converts the metadata between the in-memory datatype, mem_type_id, and the in-file + * datatype, defined when the attribute was created, without user intervention. + * + * \subsubsection subsubsec_attribute_work_access Accessing Attributes by Name or Index + * + * Attributes can be accessed by name or index value. The use of an index value makes it possible to iterate + * through all of the attributes associated with a given object. + * + * To access an attribute by its name, use the \ref H5Aopen_by_name function. \ref H5Aopen_by_name returns an + * attribute identifier that can then be used by any function that must access an attribute such as \ref + * H5Aread. Use the function \ref H5Aget_name to determine an attribute’s name. + * + * To access an attribute by its index value, use the \ref H5Aopen_by_idx function. To determine an attribute + * index value when it is not already known, use the H5Oget_info function. \ref H5Aopen_by_idx is generally + * used in the course of opening several attributes for later access. Use \ref H5Aiterate if the intent is to + * perform the same operation on every attribute attached to an object. + * + * \subsubsection subsubsec_attribute_work_info Obtaining Information Regarding an Object’s Attributes + * + * In the course of working with HDF5 attributes, one may need to obtain any of several pieces of information: + * \li An attribute name + * \li The dataspace of an attribute + * \li The datatype of an attribute + * \li The number of attributes attached to an object + * + * To obtain an attribute’s name, call H5Aget_name with an attribute identifier, attr_id: + * \code + * ssize_t H5Aget_name (hid_t attr_id, size_t buf_size, char *buf) + * \endcode + * As with other attribute functions, attr_id identifies the attribute; buf_size defines the size of the + * buffer; and buf is the buffer to which the attribute’s name will be read. + * + * If the length of the attribute name, and hence the value required for buf_size, is unknown, a first call + * to \ref H5Aget_name will return that size. If the value of buf_size used in that first call is too small, + * the name will simply be truncated in buf. A second \ref H5Aget_name call can then be used to retrieve the + * name in an appropriately-sized buffer. + * + * To determine the dataspace or datatype of an attribute, call \ref H5Aget_space or \ref H5Aget_type, + * respectively: \code hid_t H5Aget_space (hid_t attr_id) hid_t H5Aget_type (hid_t attr_id) \endcode \ref + * H5Aget_space returns the dataspace identifier for the attribute attr_id. \ref H5Aget_type returns the + * datatype identifier for the attribute attr_id. + * + * To determine the number of attributes attached to an object, use the \ref H5Oget_info function. The + * function signature is below. \code herr_t H5Oget_info( hid_t object_id, H5O_info_t *object_info ) \endcode + * The number of attributes will be returned in the object_info buffer. This is generally the preferred first + * step in determining attribute index values. If the call returns N, the attributes attached to the object + * object_id have index values of 0 through N-1. + * + * \subsubsection subsubsec_attribute_work_iterate Iterating across an Object’s Attributes + * + * It is sometimes useful to be able to perform the identical operation across all of the attributes attached + * to an object. At the simplest level, you might just want to open each attribute. At a higher level, you + * might wish to perform a rather complex operation on each attribute as you iterate across the set. + * + * To iterate an operation across the attributes attached to an object, one must make a series of calls to + * \ref H5Aiterate + * \code + * herr_t H5Aiterate (hid_t obj_id, H5_index_t index_type, + * H5_iter_order_t order, hsize_t *n, H5A_operator2_t op, + * void *op_data) + * \endcode + * \ref H5Aiterate successively marches across all of the attributes attached to the object specified in + * loc_id, performing the operation(s) specified in op_func with the data specified in op_data on each + * attribute. + * + * When \ref H5Aiterate is called, index contains the index of the attribute to be accessed in this call. When + * \ref H5Aiterate returns, index will contain the index of the next attribute. If the returned index is the + * null pointer, then all attributes have been processed, and the iterative process is complete. + * + * op_func is a user-defined operation that adheres to the \ref H5A_operator_t prototype. This prototype and + * certain requirements imposed on the operator’s behavior are described in the \ref H5Aiterate entry in the + * HDF5 Reference Manual. + * + * op_data is also user-defined to meet the requirements of op_func. Beyond providing a parameter with which + * to pass this data, HDF5 provides no tools for its management and imposes no restrictions. + * + * \subsubsection subsubsec_attribute_work_delete Deleting an Attribute + * + * Once an attribute has outlived its usefulness or is no longer appropriate, it may become necessary to + * delete it. + * + * To delete an attribute, call \ref H5Adelete + * \code + * herr_t H5Adelete (hid_t loc_id, const char *name) + * \endcode + * \ref H5Adelete removes the attribute name from the group, dataset, or committed datatype specified in + * loc_id. + * + * \ref H5Adelete must not be called if there are any open attribute identifiers on the object loc_id. Such a + * call can cause the internal attribute indexes to change; future writes to an open attribute would then + * produce unintended results. + * + * \subsubsection subsubsec_attribute_work_close Closing an Attribute + * + * As is the case with all HDF5 objects, once access to an attribute it is no longer needed, that attribute + * must be closed. It is best practice to close it as soon as practicable; it is mandatory that it be closed + * prior to the H5close call closing the HDF5 Library. + * + * To close an attribute, call \ref H5Aclose + * \code + * herr_t H5Aclose (hid_t attr_id) + * \endcode + * \ref H5Aclose closes the specified attribute by terminating access to its identifier, attr_id. + * + * \subsection subsec_attribute_special Special Issues + * + * Some special issues for attributes are discussed below. + * + *

Large Numbers of Attributes Stored in Dense Attribute Storage

+ * + * The dense attribute storage scheme was added in version 1.8 so that datasets, groups, and committed + * datatypes that have large numbers of attributes could be processed more quickly. + * + * Attributes start out being stored in an object's header. This is known as compact storage. For more + * information, see "Storage Strategies." + * + * As the number of attributes grows, attribute-related performance slows. To improve performance, dense + * attribute storage can be initiated with the H5Pset_attr_phase_change function. See the HDF5 Reference + * Manual for more information. + * + * When dense attribute storage is enabled, a threshold is defined for the number of attributes kept in + * compact storage. When the number is exceeded, the library moves all of the attributes into dense storage + * at another location. The library handles the movement of attributes and the pointers between the locations + * automatically. If some of the attributes are deleted so that the number falls below the threshold, then + * the attributes are moved back to compact storage by the library. + * + * The improvements in performance from using dense attribute storage are the result of holding attributes + * in a heap and indexing the heap with a B-tree. + * + * Note that there are some disadvantages to using dense attribute storage. One is that this is a new feature. + * Datasets, groups, and committed datatypes that use dense storage cannot be read by applications built with + * earlier versions of the library. Another disadvantage is that attributes in dense storage cannot be + * compressed. + * + *

Large Attributes Stored in Dense Attribute Storage

+ * + * We generally consider the maximum size of an attribute to be 64K bytes. The library has two ways of storing + * attributes larger than 64K bytes: in dense attribute storage or in a separate dataset. Using dense + * attribute storage is described in this section, and storing in a separate dataset is described in the next + * section. + * + * To use dense attribute storage to store large attributes, set the number of attributes that will be stored + * in compact storage to 0 with the H5Pset_attr_phase_change function. This will force all attributes to be + * put into dense attribute storage and will avoid the 64KB size limitation for a single attribute in compact + * attribute storage. + * + * The example code below illustrates how to create a large attribute that will be kept in dense storage. + * + * + * + * + * + * + *
Create
+ * \snippet{lineno} H5A_examples.c create + *
+ * + *

Large Attributes Stored in a Separate Dataset

+ * + * In addition to dense attribute storage (see above), a large attribute can be stored in a separate dataset. + * In the figure below, DatasetA holds an attribute that is too large for the object header in Dataset1. By + * putting a pointer to DatasetA as an attribute in Dataset1, the attribute becomes available to those + * working with Dataset1. + * This way of handling large attributes can be used in situations where backward compatibility is important + * and where compression is important. Applications built with versions before 1.8.x can read large + * attributes stored in separate datasets. Datasets can be compressed while attributes cannot. + * \image html Shared_Attribute.jpg "A large or shared HDF5 attribute and its associated dataset(s)" + * Note: In the figure above, DatasetA is an attribute of Dataset1 that is too large to store in Dataset1's + * header. DatasetA is associated with Dataset1 by means of an object reference pointer attached as an + * attribute to Dataset1. The attribute in DatasetA can be shared among multiple datasets by means of + * additional object reference pointers attached to additional datasets. + * + *

Shared Attributes

+ * + * Attributes written and managed through the \ref H5A interface cannot be shared. If shared attributes are + * required, they must be handled in the manner described above for large attributes and illustrated in + * the figure above. + * + *

Attribute Names

+ * + * While any ASCII or UTF-8 character may be used in the name given to an attribute, it is usually wise + * to avoid the following kinds of characters: + * \li Commonly used separators or delimiters such as slash, backslash, colon, and semi-colon (\, /, :, ;) + * \li Escape characters + * \li Wild cards such as asterisk and question mark (*, ?) + * NULL can be used within a name, but HDF5 names are terminated with a NULL: whatever comes after the NULL + * will be ignored by HDF5. + * + * The use of ASCII or UTF-8 characters is determined by the character encoding property. See + * H5Pset_char_encoding in the HDF5 Reference Manual. + * + *

No Special I/O or Storage

+ * + * HDF5 attributes have all the characteristics of HDF5 datasets except the following: + * \li Attributes are written and read only in full: there is no provision for partial I/O or sub-setting + * \li No special storage capability is provided for attributes: there is no compression or chunking, and + * attributes are not extendable + * + * \defgroup H5A H5A + * + * An HDF5 attribute is a small metadata object describing the nature and/or intended usage of a primary data + * object. A primary data object may be a dataset, group, or committed datatype. + * + * See \ref sec_attribute + * */ #endif /* H5Amodule_H */ diff --git a/src/H5Emodule.h b/src/H5Emodule.h index 58a3517..e9f2aab 100644 --- a/src/H5Emodule.h +++ b/src/H5Emodule.h @@ -29,30 +29,556 @@ #define H5_MY_PKG_ERR H5E_ERROR #define H5_MY_PKG_INIT YES -/**\defgroup H5E H5E - * - * Use the functions in this module to manage HDF5 error stacks and error - * messages. - * - * - * - * - * - * - * - * - * - * - * - *
CreateRead
- * \snippet{lineno} H5E_examples.c create - * - * \snippet{lineno} H5E_examples.c read - *
UpdateDelete
- * \snippet{lineno} H5E_examples.c update - * - * \snippet{lineno} H5E_examples.c delete - *
+/** \page H5E_UG HDF5 Error Handling + * + * \section sec_error HDF5 Error Handling + * + * The HDF5 library provides an error reporting mechanism for both the library itself and for user + * application programs. It can trace errors through function stack and error information like file + * name, function name, line number, and error description. + * + * \subsection subsec_error_intro Introduction + * The HDF5 Library provides an error reporting mechanism for both the library itself and for user application + * programs. It can trace errors through function stack and error information like file name, function name, + * line number, and error description. + * + * \ref subsec_error_ops discusses the basic error concepts such as error stack, error record, and error + * message and describes the related API functions. These concepts and functions are sufficient for + * application programs to trace errors inside the HDF5 Library. + * + * \ref subsec_error_adv talks about the advanced concepts of error + * class and error stack handle and talks about the related functions. With these concepts and functions, an + * application library or program using the HDF5 Library can have its own error report blended with HDF5’s + * error report. + * + * Starting with Release 1.8, we have a new set of Error Handling API functions. For the purpose of backward + * compatibility with version 1.6 and before, we still keep the old API functions, \ref H5Epush1, + * \ref H5Eprint1, \ref H5Ewalk1, \ref H5Eclear1, \ref H5Eget_auto1, \ref H5Eset_auto1. These functions do + * not have the error stack as a parameter. The library allows them to operate on the default error stack. + * (The H5E compatibility macros will choose the correct function based on the parameters) + * + * The old API is similar to functionality discussed in \ref subsec_error_ops. The functionality discussed in + * \ref subsec_error_adv,the ability of allowing applications to add their own error records, is the new + * design for the Error Handling API. + * + * \subsection subsec_error_H5E Error Handling Function Summaries + * \ref H5E reference manual + * + * \subsection subsec_error_program Programming Model for Error Handling + * This section is under construction. + * + * \subsection subsec_error_ops Basic Error Handling Operations + * Let us first try to understand the error stack. An error stack is a collection of error records. Error + * records can be pushed onto or popped off the error stack. By default, when an error occurs deep within + * the HDF5 Library, an error record is pushed onto an error stack and that function returns a failure + * indication. + * Its caller detects the failure, pushes another record onto the stack, and returns a failure indication. + * This continues until the API function called by the application returns a failure indication. The next + * API function being called will reset the error stack. All HDF5 Library error records belong to the same + * error class. For more information, see \ref subsec_error_adv. + * + * \subsubsection subsubsec_error_ops_stack Error Stack and Error Message + * In normal circumstances, an error causes the stack to be printed on the standard error stream + * automatically. + * This automatic error stack is the library’s default stack. For all the functions in this section, whenever + * an error stack ID is needed as a parameter, \ref H5E_DEFAULT can be used to indicate the library’s default + * stack. The first error record of the error stack, number #000, is produced by the API function itself and + * is usually sufficient to indicate to the application what went wrong. + * + * + * + * + * + *
Example: An Error Message
+ *

If an application calls \ref H5Tclose on a + * predefined datatype then the following message is + * printed on the standard error stream. This is a + * simple error that has only one component, the API + * function; other errors may have many components. + *

+ * HDF5-DIAG: Error detected in HDF5 (1.10.9) thread 0.
+ *    #000: H5T.c line ### in H5Tclose(): predefined datatype
+ *       major: Function argument
+ *       minor: Bad value
+ *         
+ *
+ * In the example above, we can see that an error record has a major message and a minor message. A major + * message generally indicates where the error happens. The location can be a dataset or a dataspace, for + * example. A minor message explains further details of the error. An example is “unable to open file”. + * Another specific detail about the error can be found at the end of the first line of each error record. + * This error description is usually added by the library designer to tell what exactly goes wrong. In the + * example above, the “predefined datatype” is an error description. + * + * \subsubsection subsubsec_error_ops_print Print and Clear an Error Stack + * Besides the automatic error report, the error stack can also be printed and cleared by the functions + * \ref H5Eprint2 and \ref H5Eclear2. If an application wishes to make explicit + * calls to \ref H5Eprint2 to print the error stack, the automatic printing should be turned off + * to prevent error messages from being displayed twice (see \ref H5Eset_auto2). + * + * To print an error stack: + * \code + * herr_t H5Eprint2(hid_t error_stack, FILE * stream) + * \endcode + * This function prints the error stack specified by error_stack on the specified stream, stream. If the + * error stack is empty, a one‐line message will be printed. The following is an example of such a message. + * This message would be generated if the error was in the HDF5 Library. + * \code + * HDF5-DIAG: Error detected in HDF5 Library version: 1.10.9 thread 0. + * \endcode + * + * To clear an error stack: + * \code + * herr_t H5Eclear2(hid_t error_stack) + * \endcode + * The \ref H5Eclear2 function shown above clears the error stack specified by error_stack. + * \ref H5E_DEFAULT can be passed in to clear the current error stack. The current stack is also cleared + * whenever an API function is called; there are certain exceptions to this rule such as \ref H5Eprint2. + * + * \subsubsection subsubsec_error_ops_mute Mute Error Stack + * Sometimes an application calls a function for the sake of its return value, fully expecting the function + * to fail; sometimes the application wants to call \ref H5Eprint2 explicitly. In these situations, + * it would be misleading if an error message were still automatically printed. Using the + * \ref H5Eset_auto2 function can control the automatic printing of error messages. + * + * To enable or disable automatic printing of errors: + * \code + * herr_t H5Eset_auto2(hid_t error_stack, H5E_auto_t func, void *client_data) + * \endcode + * The \ref H5Eset_auto2 function can be used to turn on or off the automatic printing of errors + * for the error stack specified by error_stack. When turned on (non‐null func pointer), any API function + * which returns an error indication will first call func, passing it client_data as an argument. When the + * library is first initialized the auto printing function is set to \ref H5Eprint2 and client_data + * is the standard error stream pointer, stderr. + * + * To see the current settings: + * \code + * herr_t H5Eget_auto(hid_t error_stack, H5E_auto_t * func, void **client_data) + * \endcode + * The function above returns the current settings for the automatic error stack traversal function, func, and + * its data, client_data. If either or both of the arguments are null, then the value is not returned. + * + * + * + * + * + * + *
Example: Turn off error messages while probing a function
+ *

An application can temporarily turn off error messages while “probing” a function. See the + * example below. + *

+ * ***  Save old error handler  ***
+ * H5E_auto2_t oldfunc;
+ * void *old_client_data;
+ * H5Eget_auto2(error_stack, &old_func, &old_client_data);
+ * ***  Turn off error handling  ***
+ * H5Eset_auto2(error_stack, NULL, NULL);
+ * ***  Probe. Likely to fail, but that’s okay  ***
+ * status = H5Fopen (......);
+ * ***  Restore previous error handler  ***
+ * H5Eset_auto2(error_stack, old_func, old_client_data);
+ *         
+ *
+ * + * + * + * + * + * + *
Example: Disable automatic printing and explicitly print error messages
+ *

Or automatic printing can be disabled altogether and error messages can be explicitly printed. + *

+ * ***  Turn off error handling permanently  ***
+ * H5Eset_auto2(error_stack, NULL, NULL);
+ * ***  If failure, print error message  ***
+ * if (H5Fopen (....)<0) {
+ *     H5Eprint2(H5E_DEFAULT, stderr);
+ * exit (1);
+ * }
+ *         
+ *
+ * + * + * \subsubsection subsubsec_error_ops_custom_print Customized Printing of an Error Stack + * Applications are allowed to define an automatic error traversal function other than the default + * \ref H5Eprint(). For instance, one can define a function that prints a simple, one‐line error message to + * the standard error stream and then exits. The first example below defines a such a function. The second + * example below installs the function as the error handler. + * + * + * + * + * + * + *
Example: Defining a function to print a simple error message
+ *

+ * herr_t
+ * my_hdf5_error_handler(void *unused)
+ * {
+ *     fprintf (stderr, “An HDF5 error was detected. Bye.\\n”);
+ *     exit (1);
+ * }
+ *
+ *         
+ *
+ * + * + * + * + * + * + *
Example: The user‐defined error handler
+ *

+ * H5Eset_auto2(H5E_DEFAULT, my_hdf5_error_handler, NULL);
+ *         
+ *
+ * + * \subsubsection subsubsec_error_ops_walk Walk through the Error Stack + * The \ref H5Eprint2 function is actually just a wrapper around the more complex \ref H5Ewalk function + * which traverses an error stack and calls a user‐defined function for each member of the stack. The example + * below shows how \ref H5Ewalk is used. + * \code + * herr_t H5Ewalk(hid_t err_stack, H5E_direction_t direction, + * H5E_walk_t func, void *client_data) + * \endcode + * The error stack err_stack is traversed and func is called for each member of the stack. Its arguments + * are an integer sequence number beginning at zero (regardless of direction) and the client_data + * pointer. If direction is \ref H5E_WALK_UPWARD, then traversal begins at the inner‐most function that + * detected the error and concludes with the API function. Use \ref H5E_WALK_DOWNWARD for the opposite + * order. + * + * \subsubsection subsubsec_error_ops_travers Traverse an Error Stack with a Callback Function + * An error stack traversal callback function takes three arguments: n is a sequence number beginning at + * zero for each traversal, eptr is a pointer to an error stack member, and client_data is the same pointer + * used in the example above passed to \ref H5Ewalk. See the example below. + * \code + * typedef herr_t (*H5E_walk_t)(unsigned n, H5E_error2_t *eptr, void *client_data) + * \endcode + * The H5E_error2_t structure is shown below. + * \code + * typedef struct { + * hid_t cls_id; + * hid_t maj_num; + * hid_t min_num; + * unsigned line; + * const char *func_name; + * const char *file_name; + * const char *desc; + * } H5E_error2_t; + * \endcode + * The maj_num and min_num are major and minor error IDs, func_name is the name of the function where + * the error was detected, file_name and line locate the error within the HDF5 Library source code, and + * desc points to a description of the error. + * + * + * + * + * + * + *
Example: A user‐defined callback function
+ *

The following example shows a user‐defined callback function. + *

+ *     \#define MSG_SIZE 64
+ *     herr_t
+ *     custom_print_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data)
+ *     {
+ *         FILE *stream = (FILE *)client_data;
+ *         char maj[MSG_SIZE];
+ *         char min[MSG_SIZE];
+ *         char cls[MSG_SIZE];
+ *         const int indent = 4;
+ *
+ *         ***  Get descriptions for the major and minor error numbers  ***
+ *         if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE) < 0)
+ *             TEST_ERROR;
+ *         if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE) < 0)
+ *             TEST_ERROR;
+ *         if(H5Eget_msg(err_desc->min_num, NULL, min, MSG_SIZE) < 0)
+ *             TEST_ERROR;
+ *         fprintf (stream, “%*serror #%03d: %s in %s():
+ *                 line %u\\n”,
+ *                 indent, “”, n, err_desc->file_name,
+ *                 err_desc->func_name, err_desc->line);
+ *         fprintf (stream, “%*sclass: %s\\n”, indent*2, “”, cls);
+ *         fprintf (stream, “%*smajor: %s\\n”, indent*2, “”, maj);
+ *         fprintf (stream, “%*sminor: %s\\n”, indent*2, “”, min);
+ *         return 0;
+ *     error:
+ *         return -1;
+ *     }
+ *         
+ *
+ * + *

Programming Note for C++ Developers Using C Functions

+ * If a C routine that takes a function pointer as an argument is called from within C++ code, the C routine + * should be returned from normally. + * + * Examples of this kind of routine include callbacks such as \ref H5Pset_elink_cb and + * \ref H5Pset_type_conv_cb and + * functions such as \ref H5Tconvert and \ref H5Ewalk2. + * + * Exiting the routine in its normal fashion allows the HDF5 C Library to clean up its work properly. In other + * words, if the C++ application jumps out of the routine back to the C++ “catch” statement, the library is + * not given the opportunity to close any temporary data structures that were set up when the routine was + * called. The C++ application should save some state as the routine is started so that any problem that + * occurs might be diagnosed. + * + * \subsection subsec_error_adv Advanced Error Handling Operations + * The section above, see \ref subsec_error_ops, discusses the basic error + * handling operations of the library. In that section, all the error records on the error stack are from the + * library itself. In this section, we are going to introduce the operations that allow an application program + * to push its own error records onto the error stack once it declares an error class of its own through the + * HDF5 Error API. + * + * + * + * + * + * + *
Example: An Error Report
+ *

An error report shows both the library’s error record and the application’s error records. + * See the example below. + *

+ * Error Test-DIAG: Error detected in Error Program (1.0)
+ *         thread 8192:
+ *     #000: ../../hdf5/test/error_test.c line ### in main():
+ *         Error test failed
+ *       major: Error in test
+ *       minor: Error in subroutine
+ *     #001: ../../hdf5/test/error_test.c line ### in
+ *         test_error(): H5Dwrite failed as supposed to
+ *       major: Error in IO
+ *       minor: Error in H5Dwrite
+ *   HDF5-DIAG: Error detected in HDF5 (1.10.9) thread #####:
+ *     #002: ../../hdf5/src/H5Dio.c line ### in H5Dwrite():
+ *         not a dataset
+ *       major: Invalid arguments to routine
+ *       minor: Inappropriate type
+ *         
+ *
+ * In the line above error record #002 in the example above, the starting phrase is HDF5. This is the error + * class name of the HDF5 Library. All of the library’s error messages (major and minor) are in this default + * error class. The Error Test in the beginning of the line above error record #000 is the name of the + * application’s error class. The first two error records, #000 and #001, are from application’s error class. + * By definition, an error class is a group of major and minor error messages for a library (the HDF5 Library + * or an application library built on top of the HDF5 Library) or an application program. The error class can + * be registered for a library or program through the HDF5 Error API. Major and minor messages can be defined + * in an error class. An application will have object handles for the error class and for major and minor + * messages for further operation. See the example below. + * + * + * + * + * + * + *
Example: The user‐defined error handler
+ *

+ * \#define MSG_SIZE 64
+ * herr_t
+ * custom_print_cb(unsigned n, const H5E_error2_t *err_desc,
+ * void* client_data)
+ * {
+ *     FILE *stream = (FILE *)client_data;
+ *     char maj[MSG_SIZE];
+ *     char min[MSG_SIZE];
+ *     char cls[MSG_SIZE];
+ *     const int indent = 4;
+ *
+ *     ***  Get descriptions for the major and minor error numbers  ***
+ *     if(H5Eget_class_name(err_desc->cls_id, cls, MSG_SIZE) < 0)
+ *         TEST_ERROR;
+ *     if(H5Eget_msg(err_desc->maj_num, NULL, maj, MSG_SIZE) < 0)
+ *         TEST_ERROR;
+ *     if(H5Eget_msg(err_desc->min_num, NULL, min, MSG_SIZE) < 0)
+ *         TEST_ERROR;
+ *     fprintf (stream, “%*serror #%03d: %s in %s():
+ *             line %u\\n”,
+ *             indent, “”, n, err_desc->file_name,
+ *             err_desc->func_name, err_desc->line);
+ *     fprintf (stream, “%*sclass: %s\\n”, indent*2, “”, cls);
+ *     fprintf (stream, “%*smajor: %s\\n”, indent*2, “”, maj);
+ *     fprintf (stream, “%*sminor: %s\\n”, indent*2, “”, min);
+ *     return 0;
+ * error:
+ *     return -1;
+ * }
+ *         
+ *
+ * + * \subsubsection subsubsec_error_adv_more More Error API Functions + * The Error API has functions that can be used to register or unregister an error class, to create or close + * error messages, and to query an error class or error message. These functions are illustrated below. + * + * To register an error class: + * \code + * hid_t H5Eregister_class(const char* cls_name, const char* lib_name, const char* version) + * \endcode + * This function registers an error class with the HDF5 Library so that the application library or program + * can report errors together with the HDF5 Library. + * + * To add an error message to an error class: + * \code + * hid_t H5Ecreate_msg(hid_t class, H5E_type_t msg_type, const char* mesg) + * \endcode + * This function adds an error message to an error class defined by an application library or program. The + * error message can be either major or minor which is indicated by parameter msg_type. + * + * To get the name of an error class: + * \code + * ssize_t H5Eget_class_name(hid_t class_id, char* name, size_t size) + * \endcode + * This function retrieves the name of the error class specified by the class ID. + * + * To retrieve an error message: + * \code + * ssize_t H5Eget_msg(hid_t mesg_id, H5E_type_t* mesg_type, char* mesg, size_t size) + * \endcode + * This function retrieves the error message including its length and type. + * + * To close an error message: + * \code + * herr_t H5Eclose_msg(hid_t mesg_id) + * \endcode + * This function closes an error message. + * + * To remove an error class: + * \code + * herr_t H5Eunregister_class(hid_t class_id) + * \endcode + * This function removes an error class from the Error API. + * + * + * + * + * + * + *
Example: Create an error class and error messages
+ *

The example below shows how an application creates an error class and error messages. + *

+ * ***  Create an error class  ***
+ * class_id = H5Eregister_class(ERR_CLS_NAME, PROG_NAME, PROG_VERS);
+ * ***  Retrieve class name  ***
+ * H5Eget_class_name(class_id, cls_name, cls_size);
+ * ***  Create a major error message in the class  ***
+ * maj_id = H5Ecreate_msg(class_id, H5E_MAJOR, “... ...”);
+ * ***  Create a minor error message in the class  ***
+ * min_id = H5Ecreate_msg(class_id, H5E_MINOR, “... ...”);
+ *         
+ *
+ * + * + * + * + * + * + *
Example: Closing error messages and unregistering the error class
+ *

The example below shows how an application closes error messages and unregisters the error + * class. + *

+ *    H5Eclose_msg(maj_id);
+ *    H5Eclose_msg(min_id);
+ *    H5Eunregister_class(class_id);
+ *         
+ *
+ * + * \subsubsection subsubsec_error_adv_app Pushing an Application Error Message onto Error Stack + * An application can push error records onto or pop error records off of the error stack just as the library + * does internally. An error stack can be registered, and an object handle can be returned to the application + * so that the application can manipulate a registered error stack. + * + * To register the current stack: + * \code + * hid_t H5Eget_current_stack(void) + * \endcode + * This function registers the current error stack, returns an object handle, and clears the current error + * stack. + * An empty error stack will also be assigned an ID. + * + * To replace the current error stack with another: + * \code + * herr_t H5Eset_current_stack(hid_t error_stack) + * \endcode + * This function replaces the current error stack with another error stack specified by error_stack and + * clears the current error stack. The object handle error_stack is closed after this function call. + * + * To push a new error record to the error stack: + * \code + * herr_t H5Epush(hid_t error_stack, const char* file, const char* func, + * unsigned line, hid_t cls_id, hid_t major_id, hid_t minor_id, + * const char* desc, ... ) + * \endcode + * This function pushes a new error record onto the error stack for the current thread. + * + * To delete some error messages: + * \code + * herr_t H5Epop(hid_t error_stack, size_t count) + * \endcode + * This function deletes some error messages from the error stack. + * + * To retrieve the number of error records: + * \code + * int H5Eget_num(hid_t error_stack) + * \endcode + * This function retrieves the number of error records from an error stack. + * + * To clear the error stack: + * \code + * herr_t H5Eclear_stack(hid_t error_stack) + * \endcode + * This function clears the error stack. + * + * To close the object handle for an error stack: + * \code + * herr_t H5Eclose_stack(hid_t error_stack) + * \endcode + * This function closes the object handle for an error stack and releases its resources. + * + * + * + * + * + * + *
Example: Pushing an error message to an error stack
+ *

The example below shows how an application pushes an error record onto the default error stack. + *

+ * ***  Make call to HDF5 I/O routine  ***
+ * if((dset_id=H5Dopen(file_id, dset_name, access_plist)) < 0)
+ * {
+ *     ***  Push client error onto error stack  ***
+ *     H5Epush(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id,
+ *             CLIENT_ERR_MAJ_IO,CLIENT_ERR_MINOR_OPEN, “H5Dopen failed”);
+ * }
+ * ***  Indicate error occurred in function  ***
+ * return 0;
+ *         
+ *
+ * + * + * + * + * + * + *
Example: Registering the error stack
+ *

The example below shows how an application registers the current error stack and + * creates an object handle to avoid another HDF5 function from clearing the error stack. + *

+ * if (H5Dwrite(dset_id, mem_type_id, mem_space_id, file_space_id, dset_xfer_plist_id, buf) < 0)
+ * {
+ * ***  Push client error onto error stack  ***
+ *     H5Epush2(H5E_DEFAULT,__FILE__,FUNC,__LINE__,cls_id,
+ *             CLIENT_ERR_MAJ_IO,CLIENT_ERR_MINOR_HDF5,
+ *             “H5Dwrite failed”);
+ * ***  Preserve the error stack by assigning an object handle to it  ***
+ *     error_stack = H5Eget_current_stack();
+ * ***  Close dataset  ***
+ *     H5Dclose(dset_id);
+ * ***  Replace the current error stack with the preserved one  ***
+ *     H5Eset_current_stack(error_stack);
+ * }
+ * return 0;
+ *         
+ *
+ * + * \defgroup H5E H5E * * \internal The \c FUNC_ENTER macro clears the error stack whenever an * interface function is entered. When an error is detected, an entry @@ -77,6 +603,8 @@ * error stack. The error stack is statically allocated to reduce the * complexity of handling errors within the \ref H5E package. * + * See \ref sec_error + * */ #endif /* H5Emodule_H */ -- cgit v0.12