summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--src/H5.c9
-rw-r--r--src/H5Apublic.h3
-rw-r--r--src/H5E.c941
-rw-r--r--src/H5Eprivate.h169
-rw-r--r--src/H5Epublic.h36
-rw-r--r--src/H5G.c10
-rw-r--r--src/H5Gnode.c2
-rw-r--r--src/H5H.c2
-rw-r--r--src/H5O.c4
-rw-r--r--src/H5T.c14
-rw-r--r--src/H5private.h13
-rw-r--r--src/Makefile.in6
-rw-r--r--test/dsets.c21
-rw-r--r--test/testhdf5.c7
-rw-r--r--test/testhdf5.h88
16 files changed, 675 insertions, 651 deletions
diff --git a/MANIFEST b/MANIFEST
index e5b75f2..c113a1c 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -39,6 +39,7 @@
./html/Datasets.html
./html/Dataspaces.html
./html/Datatypes.html
+./html/Errors.html
./html/ExternalFiles.html
./html/Files.html
./html/Groups.html
diff --git a/src/H5.c b/src/H5.c
index 30a33e0..0286f47 100644
--- a/src/H5.c
+++ b/src/H5.c
@@ -185,11 +185,6 @@ H5_init_thread(void)
{
FUNC_ENTER_INIT(H5_init_thread, NULL, FAIL);
- /* Create/initialize this thread's error stack */
- if ((H5E_thrdid_g = H5Ecreate(16)) == FAIL)
- HRETURN_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL,
- "unable to create thread error stack");
-
/* Add the "thread termination" routine to the exit chain */
if (H5_add_exit(&H5_term_thread) == FAIL)
HRETURN_ERROR(H5E_FUNC, H5E_CANTINIT, FAIL,
@@ -218,9 +213,7 @@ H5_init_thread(void)
--------------------------------------------------------------------------*/
void
H5_term_thread(void)
-{
- H5Eclose(H5E_thrdid_g);
-} /* end H5_term_thread() */
+{/*void*/}
/*--------------------------------------------------------------------------
NAME
diff --git a/src/H5Apublic.h b/src/H5Apublic.h
index 9e9966e..7bc14c9 100644
--- a/src/H5Apublic.h
+++ b/src/H5Apublic.h
@@ -23,8 +23,7 @@
/* Group values allowed */
typedef enum {
BADGROUP = (-1),/*invalid Group */
- H5_ERR = 0, /*group ID for Error stack objects */
- H5_FILE, /*group ID for File objects */
+ H5_FILE = 0, /*group ID for File objects */
H5_TEMPLATE_0, /*group ID for Template objects */
H5_TEMPLATE_1, /*group ID for Template objects */
H5_TEMPLATE_2, /*group ID for Template objects */
diff --git a/src/H5E.c b/src/H5E.c
index a60d4a7..2737e34 100644
--- a/src/H5E.c
+++ b/src/H5E.c
@@ -1,598 +1,583 @@
-/****************************************************************************
-* NCSA HDF *
-* Software Development Group *
-* National Center for Supercomputing Applications *
-* University of Illinois at Urbana-Champaign *
-* 605 E. Springfield, Champaign IL 61820 *
-* *
-* For conditions of distribution and use, see the accompanying *
-* hdf/COPYING file. *
- *
- * Notes: It is safe to call HRETURN_ERROR(), HGOTO_ERROR(), HERROR(), and
- * H5ECLEAR within any of these functions except H5E_push() (see
- * comments in H5E_push()). However, some of the H5E API functions
- * don't call H5ECLEAR the the error stack on which they're operating
- * is the thread's global error stack. If the thread's global error
- * stack isn't defined yet, then HRETURN_ERROR(), HGOTO_ERROR(), and
- * HERROR() don't push an error message and H5ECLEAR just returns
- * without doing anything.
-* *
-****************************************************************************/
-
-#ifdef RCSID
-static char RcsId[] = "@(#)$Revision$";
-#endif
-
-/* $Id$ */
-
-#include <H5private.h> /* Generic Functions */
-#include <H5Aprivate.h> /* Atoms */
-#include <H5Eprivate.h> /* Private error routines */
-#include <H5MMprivate.h> /* Memory management */
-
-#define PABLO_MASK H5E_mask
-
-/*-------------------- Locally scoped variables -----------------------------*/
-
-static const H5E_major_mesg_t H5E_major_mesg_g[] =
-{
- {H5E_NONE_MAJOR, "No error"},
- {H5E_ARGS, "Invalid arguments to routine"},
- {H5E_RESOURCE, "Resource unavailable"},
- {H5E_INTERNAL, "Internal HDF5 error"},
- {H5E_FILE, "File Accessability"},
- {H5E_IO, "Low-level I/O"},
- {H5E_FUNC, "Function Entry/Exit"},
- {H5E_ATOM, "Object Atom"},
- {H5E_CACHE, "Object Cache"},
- {H5E_BTREE, "B-Tree Node"},
- {H5E_SYM, "Symbol Table"},
- {H5E_HEAP, "Heap"},
- {H5E_OHDR, "Object Header"},
- {H5E_DATATYPE, "Datatype"},
- {H5E_DATASPACE, "Dataspace"},
- {H5E_DATASET, "Dataset"},
- {H5E_STORAGE, "Data Storage"},
- {H5E_TEMPLATE, "Template"},
+/*
+ * Copyright (C) 1998 NCSA HDF
+ * All rights reserved.
+ *
+ * Purpose: Provides error handling in the form of a stack. The
+ * FUNC_ENTER() macro clears the error stack whenever an API
+ * function is entered. When an error is detected, an entry is
+ * pushed onto the stack. As the functions unwind additional
+ * entries are pushed onto the stack. The API function will
+ * return some indication that an error occurred and the
+ * application can print the error stack.
+ *
+ * Certain API functions in the H5E package (such as H5Eprint())
+ * do not clear the error stack. Otherwise, any function which
+ * doesn't have an underscore immediately after the package name
+ * will clear the error stack. For instance, H5Fopen() clears
+ * the error stack while H5F_open() does not.
+ *
+ * An error stack has a fixed maximum size. If this size is
+ * exceeded then the stack will be truncated and only the
+ * inner-most functions will have entries on the stack. This is
+ * expected to be a rare condition.
+ *
+ * Each thread has its own error stack, but since
+ * multi-threading has not been added to the library yet, this
+ * package maintains a single error stack. The error stack is
+ * statically allocated to reduce the complexity of handling
+ * errors within the H5E package.
+ *
+ */
+#include <H5private.h> /* Generic Functions */
+#include <H5Aprivate.h> /* Atoms */
+#include <H5Eprivate.h> /* Private error routines */
+#include <H5MMprivate.h> /* Memory management */
+
+#define PABLO_MASK H5E_mask
+
+static const H5E_major_mesg_t H5E_major_mesg_g[] = {
+ {H5E_NONE_MAJOR, "No error"},
+ {H5E_ARGS, "Function arguments"},
+ {H5E_RESOURCE, "Resource unavailable"},
+ {H5E_INTERNAL, "Internal HDF5 error"},
+ {H5E_FILE, "File interface"},
+ {H5E_IO, "Low-level I/O layer"},
+ {H5E_FUNC, "Function entry/exit"},
+ {H5E_ATOM, "Atom layer"},
+ {H5E_CACHE, "Meta data cache layer"},
+ {H5E_BTREE, "B-tree layer"},
+ {H5E_SYM, "Symbol table layer"},
+ {H5E_HEAP, "Heap layer"},
+ {H5E_OHDR, "Object header layer"},
+ {H5E_DATATYPE, "Datatype interface"},
+ {H5E_DATASPACE, "Dataspace interface"},
+ {H5E_DATASET, "Dataset interface"},
+ {H5E_STORAGE, "Data storage layer"},
+ {H5E_TEMPLATE, "Property list interface"},
};
-static const H5E_minor_mesg_t H5E_minor_mesg_g[] =
-{
- {H5E_NONE_MINOR, "No error"},
+static const H5E_minor_mesg_t H5E_minor_mesg_g[] = {
+ {H5E_NONE_MINOR, "No error"},
{H5E_UNINITIALIZED, "Information is uninitialized"},
- {H5E_UNSUPPORTED, "Feature is unsupported"},
- {H5E_BADTYPE, "Incorrect type found"},
- {H5E_BADRANGE, "Argument out of range"},
- {H5E_BADVALUE, "Bad value for argument"},
- {H5E_NOSPACE, "No space available for allocation"},
- {H5E_FILEEXISTS, "File already exists"},
- {H5E_FILEOPEN, "File already open"},
- {H5E_CANTCREATE, "Can't create file"},
- {H5E_CANTOPENFILE, "Can't open file"},
- {H5E_CANTOPENOBJ, "Can't open object"},
- {H5E_NOTHDF5, "Not an HDF5 format file"},
- {H5E_BADFILE, "Bad file ID accessed"},
- {H5E_TRUNCATED, "File has been truncated"},
- {H5E_SEEKERROR, "Seek failed"},
- {H5E_READERROR, "Read failed"},
- {H5E_WRITEERROR, "Write failed"},
- {H5E_CLOSEERROR, "Close failed"},
- {H5E_OVERFLOW, "Address overflowed"},
- {H5E_CANTINIT, "Can't initialize interface"},
- {H5E_ALREADYINIT, "Object already initialized"},
- {H5E_BADATOM, "Can't find atom information"},
- {H5E_CANTREGISTER, "Can't register new atom"},
- {H5E_CANTFLUSH, "Can't flush object from cache"},
- {H5E_CANTLOAD, "Can't load object into cache"},
- {H5E_PROTECT, "Protected object error"},
- {H5E_NOTCACHED, "Object not currently cached"},
- {H5E_NOTFOUND, "Object not found"},
- {H5E_EXISTS, "Object already exists"},
- {H5E_CANTENCODE, "Can't encode value"},
- {H5E_CANTDECODE, "Can't decode value"},
- {H5E_CANTSPLIT, "Can't split node"},
- {H5E_CANTINSERT, "Can't insert object"},
- {H5E_CANTLIST, "Can't list node"},
- {H5E_LINKCOUNT, "Bad object header link count"},
- {H5E_VERSION, "Wrong version number"},
- {H5E_ALIGNMENT, "Alignment error"},
- {H5E_BADMESG, "Unrecognized message"},
- {H5E_COMPLEN, "Name component is too long"},
- {H5E_CWG, "Problem with current working group"},
- {H5E_LINK, "Link count failure"},
+ {H5E_UNSUPPORTED, "Feature is unsupported"},
+ {H5E_BADTYPE, "Inappropriate type"},
+ {H5E_BADRANGE, "Out of range"},
+ {H5E_BADVALUE, "Bad value"},
+ {H5E_NOSPACE, "No space available for allocation"},
+ {H5E_FILEEXISTS, "File already exists"},
+ {H5E_FILEOPEN, "File already open"},
+ {H5E_CANTCREATE, "Unable to create file"},
+ {H5E_CANTOPENFILE, "Unable to open file"},
+ {H5E_CANTOPENOBJ, "Unable to open object"},
+ {H5E_NOTHDF5, "Not an HDF5 file"},
+ {H5E_BADFILE, "Bad file ID accessed"},
+ {H5E_TRUNCATED, "File has been truncated"},
+ {H5E_SEEKERROR, "Seek failed"},
+ {H5E_READERROR, "Read failed"},
+ {H5E_WRITEERROR, "Write failed"},
+ {H5E_CLOSEERROR, "Close failed"},
+ {H5E_OVERFLOW, "Address overflowed"},
+ {H5E_CANTINIT, "Unable to initialize"},
+ {H5E_ALREADYINIT, "Object already initialized"},
+ {H5E_BADATOM, "Unable to find atom information (already closed?)"},
+ {H5E_CANTREGISTER, "Unable to register new atom"},
+ {H5E_CANTFLUSH, "Unable to flush meta data from cache"},
+ {H5E_CANTLOAD, "Unable to load meta data into cache"},
+ {H5E_PROTECT, "Protected meta data error"},
+ {H5E_NOTCACHED, "Meta data not currently cached"},
+ {H5E_NOTFOUND, "Object not found"},
+ {H5E_EXISTS, "Object already exists"},
+ {H5E_CANTENCODE, "Unable to encode value"},
+ {H5E_CANTDECODE, "Unable to decode value"},
+ {H5E_CANTSPLIT, "Unable to split node"},
+ {H5E_CANTINSERT, "Unable to insert object"},
+ {H5E_CANTLIST, "Unable to list node"},
+ {H5E_LINKCOUNT, "Bad object header link count"},
+ {H5E_VERSION, "Wrong version number"},
+ {H5E_ALIGNMENT, "Alignment error"},
+ {H5E_BADMESG, "Unrecognized message"},
+ {H5E_COMPLEN, "Name component is too long"},
+ {H5E_CWG, "Problem with current working group"},
+ {H5E_LINK, "Link count failure"},
};
/* Interface initialization? */
-static intn interface_initialize_g = FALSE;
-#define INTERFACE_INIT H5E_init_interface
-static herr_t H5E_init_interface(void);
-static void H5E_term_interface(void);
-
-const hbool_t H5E_clearable_g = TRUE;
-hid_t H5E_thrdid_g = FAIL; /* Thread-specific "global" error-handler ID */
-
-/*--------------------------------------------------------------------------
-NAME
- H5E_init_interface -- Initialize interface-specific information
-USAGE
- herr_t H5E_init_interface()
-
-RETURNS
- SUCCEED/FAIL
-DESCRIPTION
- Initializes any interface-specific data or routines.
-
-Modifications:
- Robb Matzke, 4 Aug 1997
- Changed the pablo mask from H5_mask to H5E_mask
-
---------------------------------------------------------------------------*/
-static herr_t
-H5E_init_interface(void)
-{
- herr_t ret_value = SUCCEED;
-
- FUNC_ENTER(H5E_init_interface, FAIL);
-
- /* Initialize the atom group for the error stacks */
- if ((ret_value = H5A_init_group(H5_ERR, H5A_ERRSTACK_HASHSIZE, 0,
- (herr_t (*)(void *)) H5E_close)) != FAIL) {
- ret_value = H5_add_exit(H5E_term_interface);
- }
- FUNC_LEAVE(ret_value);
-}
+static intn interface_initialize_g = FALSE;
+#define INTERFACE_INIT NULL
+const hbool_t H5E_clearable_g = TRUE; /* DO NOT CHANGE */
+
+/*
+ * The error stack. Eventually we'll have some sort of global table so each
+ * thread has it's own stack. The stacks will be created on demand when the
+ * thread first calls H5E_push().
+ */
+H5E_t H5E_stack_g[1];
+#define H5E_get_my_stack() (H5E_stack_g+0)
+
+/*
+ * Automatic error stack traversal occurs if the traversal callback function
+ * is non null and an API function is about to return an error. These should
+ * probably be part of the error stack so they're local to a thread.
+ *
+ */
+herr_t (*H5E_auto_g)(void*) = (herr_t(*)(void*))H5Eprint;
+void *H5E_auto_data_g = stderr;
-/*--------------------------------------------------------------------------
- NAME
- H5E_term_interface
- PURPOSE
- Terminate various H5E objects
- USAGE
- void H5E_term_interface()
- RETURNS
- SUCCEED/FAIL
- DESCRIPTION
- Release the atom group and any other resources allocated.
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- Can't report errors...
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-static void
-H5E_term_interface(void)
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eset_auto
+ *
+ * Purpose: Turns on or off automatic printing of errors. 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.
+ *
+ * The default values before this function is called are
+ * H5Eprint() with client data being the standard error stream,
+ * stderr.
+ *
+ * Automatic stack traversal is always in the H5E_WALK_DOWNWARD
+ * direction.
+ *
+ * See Also: H5Ewalk()
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eset_auto (herr_t (*func)(void*client_data), void *client_data)
{
- H5A_destroy_group(H5_ERR);
+ FUNC_ENTER (H5Eset_auto, FAIL);
+
+ H5E_auto_g = func;
+ H5E_auto_data_g = client_data;
+
+ FUNC_LEAVE (SUCCEED);
}
-/*--------------------------------------------------------------------------
-NAME
- H5Ecreate -- Create a new error stack
-USAGE
- hid_t H5Ecreate (initial_stack_size);
- uintn initial_stack_size; IN: Starting size of the error stack
-
-RETURNS
- The ID of the error stack created on success, FAIL on failure.
-
-DESCRIPTION
- Dynamically creates a new error stack to push error values onto.
-
---------------------------------------------------------------------------*/
-hid_t
-H5Ecreate(uintn initial_stack_nelmts)
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_auto
+ *
+ * Purpose: Returns the current settings for the automatic error stack
+ * traversal function and its data. Either (or both) arguments
+ * may be null in which case the value is not returned.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Saturday, February 28, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5Eget_auto (herr_t (**func)(void*), void **client_data)
{
- H5E_t *new_stack = NULL; /* Pointer to the new error stack */
- hid_t ret_value = FAIL;
-
- FUNC_ENTER(H5Ecreate, FAIL);
-
- /* Check args */
- initial_stack_nelmts = MAX(10, MIN(initial_stack_nelmts, 1000));
+ FUNC_ENTER (H5Eget_auto, FAIL);
- /* Allocate the stack header */
- new_stack = H5MM_xmalloc(sizeof(H5E_t));
+ if (func) *func = H5E_auto_g;
+ if (client_data) *client_data = H5E_auto_data_g;
- /* Initialize the stack header */
- new_stack->nelmts = initial_stack_nelmts;
- new_stack->top = 0;
- new_stack->stack = H5MM_xcalloc(initial_stack_nelmts, sizeof(H5E_error_t));
- new_stack->push = H5E_push; /* Set the default error handler */
-
- /* Get an atom for the error stack */
- if ((ret_value = H5A_register(H5_ERR, new_stack)) < 0) {
- HRETURN_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL,
- "unable to register error stack");
- }
- FUNC_LEAVE(ret_value);
+ FUNC_LEAVE (SUCCEED);
}
-/*--------------------------------------------------------------------------
-NAME
- H5Eclose -- Destroy an error stack
-USAGE
- herr_t H5Eclose (err_stack);
- hid_t err_stack; IN: Error stack to delete
-
-RETURNS
- SUCCEED/FAIL
-DESCRIPTION
- Destroys an error stack, releasing memory allocated, etc.
-
---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eclear
+ *
+ * Purpose: Clears the error stack for the current thread.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL. This function can fail if there are
+ * problems initializing the library.
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
herr_t
-H5Eclose(hid_t estack_id)
+H5Eclear (void)
{
- FUNC_ENTER(H5Eclose, FAIL);
-
- /* check args */
- if (H5_ERR != H5A_group(estack_id)) {
- HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack");
- }
- /*
- * Decrement the reference count. When it reaches zero the error stack
- * will be freed.
- */
- H5A_dec_ref(estack_id);
-
- FUNC_LEAVE(SUCCEED);
+ FUNC_ENTER (H5Eclear, FAIL);
+ /* FUNC_ENTER() does all the work */
+ FUNC_LEAVE (SUCCEED);
}
+
/*-------------------------------------------------------------------------
- * Function: H5Epush
- *
- * Purpose: Pushes a new error record onto error stack ESTACK_ID. The
- * error has major and minor numbers MAJ_NUM and MIN_NUM, the
- * name of a function where the error was detected, the name of
- * the file where the error was detected, and the line within
- * that file. An error description string is also passed to
- * this function.
+ * Function: H5Eprint
*
- * The FUNCTION_NAME is copied (and possibly truncated) into a
- * fixed length character buffer; the FILE_NAME is pointed to
- * without copying it (we assume it's statically allocated from
- * __FILE__); and the DESC argument is strdup'd.
+ * Purpose: Prints the error stack in some default way. This is just a
+ * convenience function for H5Ewalk() with a function that
+ * prints error messages. Users are encouraged to write there
+ * own more specific error handlers.
*
- * It is safe to call this function before the thread global
- * error stack is initialized.
+ * Return: Success: SUCCEED
*
- * Return: Success: SUCCEED
+ * Failure: FAIL
*
- * Failure: FAIL
- *
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
-H5Epush(hid_t estack_id, H5E_major_t maj_num, H5E_minor_t min_num,
- const char *function_name, const char *file_name, intn line,
- const char *desc)
+H5Eprint (FILE *stream)
{
-
- H5E_t *estack = NULL; /* Ptr to the stack to put value on */
-
- /*
- * WARNING WARNING WARNING: We cannot call HERROR() from within this
- * function if ESTACK_ID is the thread global error stack or else we may
- * enter infinite recursion. Furthermore, we also cannot call any other
- * HDF5 macro or function which might call HERROR(). HERROR() is called
- * by HRETURN_ERROR() which could be called by FUNC_ENTER().
- */
-
- /*
- * Clear the thread global error stack only if it isn't the error stack on
- * which we're pushing the new error.
- */
- if (estack_id != H5E_thrdid_g)
- H5ECLEAR;
-
- /*
- * check args, but don't call error functions if ESTACK_ID is the thread
- * global error handler.
- */
- if (H5_ERR != H5A_group(estack_id) ||
- NULL == (estack = H5A_object(estack_id))) {
- HRETURN(FAIL);
- }
- if (!function_name || !file_name || !desc) {
- HRETURN(FAIL);
- }
- if (!estack->push) {
- HRETURN(FAIL);
- }
- /* Push the new error. It must be safe to call the push function. */
- if ((estack->push) (estack, maj_num, min_num, function_name, file_name,
- line, desc) < 0) {
- HRETURN(FAIL);
- }
- return SUCCEED; /*don't use FUNC_LEAVE() here */
+ H5E_t *estack = H5E_get_my_stack ();
+ hbool_t H5E_clearable_g = FALSE; /*override global*/
+ herr_t status = FAIL;
+
+ FUNC_ENTER (H5Eprint, FAIL);
+
+ if (!stream) stream = stderr;
+ fprintf (stream, "HDF5-DIAG: Error detected in thread 0.");
+ if (estack && estack->nused>0) fprintf (stream, " Back trace follows.");
+ fputc ('\n', stream);
+ status = H5E_walk (H5E_WALK_DOWNWARD, H5Ewalk_cb, (void*)stream);
+
+ FUNC_LEAVE (status);
}
-/*--------------------------------------------------------------------------
-NAME
- H5Eclear -- Clear an error stack for later error entries
-USAGE
- void H5Eclear(int32 err_hand)
- int32 err_hand; IN: The ID of the error stack to push the error onto.
-
-RETURNS
- SUCCEED/FAIL
-DESCRIPTION
- Clear an error stack to allow errors to be pushed onto it.
-
---------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ * Function: H5Ewalk
+ *
+ * Purpose: Walks the error stack for the current thread and calls some
+ * function for each error along the way.
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL. This function can fail if there are
+ * problems initializing the library.
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
herr_t
-H5Eclear(hid_t estack_id)
+H5Ewalk (H5E_direction_t direction, H5E_walk_t func, void *client_data)
{
- H5E_t *estack = NULL;
- hbool_t H5E_clearable_g = FALSE; /*override global*/
-
- FUNC_ENTER(H5Eclear, FAIL);
-
- /*
- * Normally we would clear the thread error stack since we're entering an
- * API function, but we have to be careful here to not get into an
- * infinite recursion.
- */
- if (estack_id != H5E_thrdid_g)
- H5ECLEAR;
+ hbool_t H5E_clearable_g = FALSE; /*override global*/
+ herr_t status = FAIL;
- /* check args */
- if (H5_ERR != H5A_group(estack_id) ||
- NULL == (estack = H5A_object(estack_id))) {
- HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack");
- }
- if (H5E_clear(estack) < 0) {
- HRETURN_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL,
- "unable to clear error stack");
- }
- FUNC_LEAVE(SUCCEED);
+ FUNC_ENTER (H5Ewalk, FAIL);
+ status = H5E_walk (direction, func, client_data);
+ FUNC_LEAVE (status);
}
+
/*-------------------------------------------------------------------------
- * Function: H5Eprint
+ * Function: H5Ewalk_cb
*
- * Purpose: Prints the current contents of error stack ESTACK_ID to the
- * stream FILE.
+ * Purpose: This is a default error stack traversal callback function
+ * that prints error messages to the specified output stream.
+ * It is not meant to be called directly but rather as an
+ * argument to the H5Ewalk() function. This function is called
+ * also by H5Eprint(). Application writers are encouraged to
+ * use this function as a model for their own error stack
+ * walking functions.
*
- * Return: Success: SUCCEED
+ * N is a counter for how many times this function has been
+ * called for this particular traversal of the stack. It always
+ * begins at zero for the first error on the stack (either the
+ * top or bottom error, or even both, depending on the traversal
+ * direction and the size of the stack).
*
- * Failure: FAIL
+ * ERR_DESC is an error description. It contains all the
+ * information about a particular error.
*
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * CLIENT_DATA is the same pointer that was passed as the
+ * CLIENT_DATA argument of H5Ewalk(). It is expected to be a
+ * file pointer (or stderr if null).
+ *
+ * Return: Success: SUCCEED
+ *
+ * Failure: FAIL
+ *
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
-H5Eprint(hid_t estack_id, FILE * file)
+H5Ewalk_cb(int n, H5E_error_t *err_desc, void *client_data)
{
- H5E_t *estack = NULL;
- hbool_t H5E_clearable_g = FALSE; /*override global*/
+ FILE *stream = (FILE *)client_data;
+ const char *maj_str = NULL;
+ const char *min_str = NULL;
+ const int indent = 2;
+
+ /* Check arguments */
+ assert (err_desc);
+ if (!client_data) client_data = stderr;
+
+ /* Get descriptions for the major and minor error numbers */
+ maj_str = H5Eget_major (err_desc->maj_num);
+ min_str = H5Eget_minor (err_desc->min_num);
+
+ /* Print error message */
+ fprintf (stream, "%*s#%03d: %s line %u in %s(): %s\n",
+ indent, "", n, err_desc->file_name, err_desc->line,
+ err_desc->func_name, err_desc->desc);
+ fprintf (stream, "%*smajor(%02d): %s\n",
+ indent*2, "", err_desc->maj_num, maj_str);
+ fprintf (stream, "%*sminor(%02d): %s\n",
+ indent*2, "", err_desc->min_num, min_str);
+
+ return SUCCEED;
+}
- FUNC_ENTER(H5Eprint, FAIL);
+
+/*-------------------------------------------------------------------------
+ * Function: H5Eget_major
+ *
+ * Purpose: Given a major error number return a constant character string
+ * that describes the error.
+ *
+ * Return: Success: Ptr to a character string.
+ *
+ * Failure: Ptr to "Invalid major error number"
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+const char *
+H5Eget_major (H5E_major_t n)
+{
+ int i;
+
/*
- * Don't clear the thread error stack if it's the one we're about to
- * print.
+ * WARNING: Do not call the FUNC_ENTER() or FUNC_LEAVE() macros since
+ * they might interact badly with the error stack. We are
+ * probably calling this function during an error stack
+ * traversal and adding/removing entries as the result of an
+ * error would most likely mess things up.
*/
- if (estack_id != H5E_thrdid_g)
- H5ECLEAR;
-
- /* check args */
- if (H5_ERR != H5A_group(estack_id) ||
- NULL == (estack = H5A_object(estack_id))) {
- HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an error stack");
+ for (i=0; i<NELMTS (H5E_major_mesg_g); i++) {
+ if (H5E_major_mesg_g[i].error_code==n) {
+ return H5E_major_mesg_g[i].str;
+ }
}
- if (!file)
- file = stderr;
- /* print it */
- if (H5E_print(estack, file) < 0) {
- HRETURN_ERROR(H5E_INTERNAL, H5E_CANTINIT, FAIL,
- "can't print error stack");
- }
- FUNC_LEAVE(SUCCEED);
+ return "Invalid major error number";
}
+
/*-------------------------------------------------------------------------
- * Function: H5E_close
+ * Function: H5Eget_minor
*
- * Purpose: Frees resources associated with an error stack.
+ * Purpose: Given a minor error number return a constant character string
+ * that describes the error.
*
- * Return: Success: SUCCEED
+ * Return: Success: Ptr to a character string.
*
- * Failure: FAIL
+ * Failure: Ptr to "Invalid minor error number"
*
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-herr_t
-H5E_close(H5E_t *estack)
+const char *
+H5Eget_minor (H5E_minor_t n)
{
- FUNC_ENTER(H5E_close, FAIL);
-
- /* check args */
- assert(estack);
-
- /* clear error stack, then free it */
- H5E_clear(estack);
- H5MM_xfree(estack->stack);
- H5MM_xfree(estack);
+ int i;
+
+ /*
+ * WARNING: Do not call the FUNC_ENTER() or FUNC_LEAVE() macros since
+ * they might interact badly with the error stack. We are
+ * probably calling this function during an error stack
+ * traversal and adding/removing entries as the result of an
+ * error would most likely mess things up.
+ */
+ for (i=0; i<NELMTS (H5E_minor_mesg_g); i++) {
+ if (H5E_minor_mesg_g[i].error_code==n) {
+ return H5E_minor_mesg_g[i].str;
+ }
+ }
- FUNC_LEAVE(SUCCEED);
+ return "Invalid minor error number";
}
+
/*-------------------------------------------------------------------------
- * Function: H5E_clear
+ * Function: H5E_push
*
- * Purpose: Clears an error stack but does not release the stack.
+ * Purpose: Pushes a new error record onto error stack for the current
+ * thread. The error has major and minor numbers MAJ_NUM and
+ * MIN_NUM, the name of a function where the error was detected,
+ * the name of the file where the error was detected, the
+ * line within that file, and an error description string. The
+ * function name, file name, and error description strings must
+ * be statically allocated (the FUNC_ENTER() macro takes care of
+ * the function name and file name automatically, but the
+ * programmer is responsible for the description string).
*
- * Return: Success: SUCCEED
+ * Return: Success: SUCCEED
*
- * Failure: FAIL
+ * Failure: FAIL
*
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
-H5E_clear(H5E_t *estack)
+H5E_push(H5E_major_t maj_num, H5E_minor_t min_num, const char *function_name,
+ const char *file_name, unsigned line, const char *desc)
{
- int i;
-
- FUNC_ENTER(H5E_clear, FAIL);
+ H5E_t *estack = H5E_get_my_stack ();
+
+ /*
+ * WARNING: We cannot call HERROR() from within this function or else we
+ * could enter infinite recursion. Furthermore, we also cannot
+ * call any other HDF5 macro or function which might call
+ * HERROR(). HERROR() is called by HRETURN_ERROR() which could
+ * be called by FUNC_ENTER().
+ */
- /* check args */
- assert(estack);
+ /*
+ * Don't fail if arguments are bad. Instead, substitute some default
+ * value.
+ */
+ if (!function_name) function_name = "Unknown_Function";
+ if (!file_name) file_name = "Unknown_File";
+ if (!desc) desc = "No description given";
- /* Clear the error descriptions and reset the stack top */
- for (i = 0; i < estack->top; i++) {
- H5MM_xfree(estack->stack[i].desc);
- estack->stack[i].desc = NULL;
+ /*
+ * Push the error if there's room. Otherwise just forget it.
+ */
+ assert (estack);
+ if (estack->nused<H5E_NSLOTS) {
+ estack->slot[estack->nused].maj_num = maj_num;
+ estack->slot[estack->nused].min_num = min_num;
+ estack->slot[estack->nused].func_name = function_name;
+ estack->slot[estack->nused].file_name = file_name;
+ estack->slot[estack->nused].line = line;
+ estack->slot[estack->nused].desc = desc;
+ estack->nused++;
}
- estack->top = 0;
-
- FUNC_LEAVE(SUCCEED);
+
+ return SUCCEED; /*don't use FUNC_LEAVE() here */
}
+
/*-------------------------------------------------------------------------
- * Function: H5E_push
- *
- * Purpose: Push an error onto an error stack. The FUNCTION_NAME is
- * copied (and possibly truncated) into the error record. The
- * FILE_NAME pointer is used directly since we assume it came
- * from the __FILE__ construct and is thus static data. The
- * description, DESC, is strdup'd into the error record.
+ * Function: H5E_clear
*
- * Note: Warning: to prevent infinite recursivion this function must
- * not call any other HDF5 function and especially not
- * the HDF5 error handling macros.
+ * Purpose: Clears the error stack for the current thread.
*
- * Return: Success: SUCCEED
+ * Return: Success: SUCCEED
*
- * Failure: FAIL
+ * Failure: FAIL. This function can fail if there are
+ * problems initializing the library.
*
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * Programmer: Robb Matzke
+ * Friday, February 27, 1998
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
-H5E_push(H5E_t *estack, H5E_major_t maj_num, H5E_minor_t min_num,
- const char *function_name, const char *file_name, intn line,
- const char *desc)
+H5E_clear(void)
{
+ H5E_t *estack = H5E_get_my_stack ();
- /* FUNC_ENTER (H5E_push, FAIL); -- can't do this here! */
-
- /* check args */
- assert(estack);
- assert(function_name);
- assert(file_name);
-
- /* Check if we need to expand the stack */
- if (estack->top >= estack->nelmts) {
- /*
- * Ask for new stack that's twice as large. Do not use hdf5 functions
- * to allocate the memory!
- */
- estack->nelmts *= 2;
- estack->stack = realloc(estack->stack,
- estack->nelmts * sizeof(H5E_error_t));
- assert(estack->stack);
- }
- /* Push the error onto the error stack */
- estack->stack[estack->top].maj_num = maj_num;
- estack->stack[estack->top].min_num = min_num;
- HDstrncpy(estack->stack[estack->top].func_name, function_name,
- MAX_FUNC_NAME);
- estack->stack[estack->top].func_name[MAX_FUNC_NAME - 1] = '\0';
- estack->stack[estack->top].file_name = file_name;
- estack->stack[estack->top].line = line;
-
- /* strdup the description but don't use H5MM_xstrdup() */
- estack->stack[estack->top].desc = malloc(strlen(desc) + 1);
- assert(estack->stack[estack->top].desc);
- strcpy(estack->stack[estack->top].desc, desc);
-
- /* Increment the top of the error stack */
- estack->top++;
-
- return SUCCEED; /*don't use FUNC_LEAVE() here */
+ FUNC_ENTER(H5E_clear, FAIL);
+ if (estack) estack->nused = 0;
+ FUNC_LEAVE(SUCCEED);
}
+
/*-------------------------------------------------------------------------
- * Function: H5E_print
+ * Function: H5E_walk
+ *
+ * Purpose: Walks the error stack, calling the specified function for
+ * each error on the stack. The DIRECTION argument determines
+ * whether the stack is walked from the inside out or the
+ * outside in. The value H5E_WALK_UPWARD means begin with the
+ * most specific error and end at the API; H5E_WALK_DOWNWARD
+ * means to start at the API and end at the inner-most function
+ * where the error was first detected.
*
- * Purpose: Prints an error stack ESTACK to the stream FILE.
+ * The function pointed to by FUNC will be called for each error
+ * in the error stack. It's arguments will include an index
+ * number (beginning at zero regardless of stack traversal
+ * direction), an error stack entry, and the CLIENT_DATA pointer
+ * passed to H5E_print.
*
- * Return: Success: SUCCEED
+ * Return: Success: SUCCEED
*
- * Failure: FAIL
+ * Failure: FAIL. This function can fail if there are
+ * problems initializing the library.
*
- * Programmer: Robb Matzke
- * Friday, December 12, 1997
+ * Programmer: Robb Matzke
+ * Friday, December 12, 1997
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
herr_t
-H5E_print(H5E_t *estack, FILE * file)
+H5E_walk (H5E_direction_t direction, H5E_walk_t func, void *client_data)
{
- intn i, j;
- const char *maj_str = NULL;
- const char *min_str = NULL;
-
- FUNC_ENTER(H5E_print, FAIL);
-
- /* check args */
- assert(estack);
- assert(file);
-
- if (0 == estack->top)
- HRETURN(SUCCEED);
-
- fprintf(file, "HDF5-DIAG: error stack:\n");
- for (i = 0; i < estack->top; i++) {
-
- /* Find major and minor error strings */
- for (j = 0, maj_str = "??"; j < NELMTS(H5E_major_mesg_g); j++) {
- if (H5E_major_mesg_g[j].error_code == estack->stack[i].maj_num) {
- maj_str = H5E_major_mesg_g[j].str;
- break;
- }
- }
- for (j = 0, min_str = "??"; j < NELMTS(H5E_minor_mesg_g); j++) {
- if (H5E_minor_mesg_g[j].error_code == estack->stack[i].min_num) {
- min_str = H5E_minor_mesg_g[j].str;
- break;
- }
- }
-
- /* Print error message */
- fprintf(file, " #%03d: %s:%d in %s() error %02d/%02d: %s\n",
- i, estack->stack[i].file_name, estack->stack[i].line,
- estack->stack[i].func_name, estack->stack[i].maj_num,
- estack->stack[i].min_num, estack->stack[i].desc);
- fprintf(file, " %s (%s)\n", maj_str, min_str);
+ H5E_t *estack = H5E_get_my_stack ();
+ int i;
+ herr_t status;
+
+ FUNC_ENTER(H5E_walk, FAIL);
+
+ /* check args, but rather than failing use some default value */
+ if (direction!=H5E_WALK_UPWARD && direction!=H5E_WALK_DOWNWARD) {
+ direction = H5E_WALK_UPWARD;
}
+ /* walk the stack */
+ assert (estack);
+ if (func && H5E_WALK_UPWARD==direction) {
+ for (i=0, status=SUCCEED; i<estack->nused && status>=0; i++) {
+ status = (func)(i, estack->slot+i, client_data);
+ }
+ } else if (func && H5E_WALK_DOWNWARD==direction) {
+ for (i=estack->nused-1, status=SUCCEED; i>=0 && status>=0; --i) {
+ status = (func)(estack->nused-(i+1), estack->slot+i, client_data);
+ }
+ }
+
FUNC_LEAVE(SUCCEED);
}
+
diff --git a/src/H5Eprivate.h b/src/H5Eprivate.h
index 8b59828..885ad44 100644
--- a/src/H5Eprivate.h
+++ b/src/H5Eprivate.h
@@ -1,13 +1,13 @@
/****************************************************************************
- * NCSA HDF *
- * Software Development Group *
- * National Center for Supercomputing Applications *
- * University of Illinois at Urbana-Champaign *
- * 605 E. Springfield, Champaign IL 61820 *
- * *
- * For conditions of distribution and use, see the accompanying *
- * hdf/COPYING file. *
- * *
+ * NCSA HDF *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * *
+ * For conditions of distribution and use, see the accompanying *
+ * hdf/COPYING file. *
+ * *
****************************************************************************/
/*
@@ -21,113 +21,94 @@
/* Private headers needed by this file */
#include <H5private.h>
-/*
- ======================================================================
- Error codes
+#define H5E_NSLOTS 32 /*number of slots in an error stack */
- NOTE: Remember to update the error_messages[] structure later in this file
- whenever errors are added/deleted from this list.
- ======================================================================
+/*
+ * HERROR macro, used to facilitate error reporting between a FUNC_ENTER()
+ * and a FUNC_LEAVE() within a function body. The arguments are the major
+ * error number, the minor error number, and a description of the error.
*/
+#define HERROR(maj, min, str) H5E_push(maj, min, FUNC, __FILE__, __LINE__, str)
-/* HERROR macro, used to facilitate error reporting. Assumes that
- there's a variable called FUNC which holds the function name.
- Assume that func and file are both stored in static space, or at
- least be not corrupted in the meanwhile. */
-#define HERROR(maj, min, str) H5Epush (H5E_thrdid_g, maj, min, \
- FUNC, __FILE__, __LINE__, str)
-
-/* HRETURN_ERROR macro, used to facilitate error reporting. Makes
- same assumptions as HERROR. IN ADDITION, this macro causes
- a return from the calling routine */
-#define HRETURN_ERROR(maj, min, ret_val, str) { \
- HERROR (maj, min, str); \
- PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \
- return (ret_val); \
+/*
+ * HRETURN_ERROR macro, used to facilitate error reporting between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are
+ * the major error number, the minor error number, a return value, and a
+ * description of the error.
+ */
+#define HRETURN_ERROR(maj, min, ret_val, str) { \
+ HERROR (maj, min, str); \
+ if (H5_IS_API(FUNC) && H5E_auto_g) { \
+ (H5E_auto_g)(H5E_auto_data_g); \
+ } \
+ PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \
+ return (ret_val); \
}
-/* HRETURN macro, similar to HRETURN_ERROR() except for success */
-#define HRETURN(ret_val) { \
- PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \
- return (ret_val); \
+/*
+ * HRETURN macro, used to facilitate returning from a function between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The argument is
+ * the return value.
+ */
+#define HRETURN(ret_val) { \
+ PABLO_TRACE_OFF (PABLO_MASK, pablo_func_id); \
+ return (ret_val); \
}
-/* HGOTO_ERROR macro, used to facilitate error reporting. Makes
- same assumptions as HERROR. IN ADDITION, this macro causes
- a jump to the label 'done' which should be in every fucntion
- Also there is an assumption of a variable 'ret_value' */
-#define HGOTO_ERROR(maj, min, ret_val, str) { \
- HERROR (maj, min, str); \
- ret_value = ret_val; \
- goto done; \
+/*
+ * HGOTO_ERROR macro, used to facilitate error reporting between a
+ * FUNC_ENTER() and a FUNC_LEAVE() within a function body. The arguments are
+ * the major error number, the minor error number, the return value, and an
+ * error string. The return value is assigned to a variable `ret_value' and
+ * control branches to the `done' label.
+ */
+#define HGOTO_ERROR(maj, min, ret_val, str) { \
+ HERROR (maj, min, str); \
+ if (H5_IS_API(FUNC) && H5E_auto_g) { \
+ (H5E_auto_g)(H5E_auto_data_g); \
+ } \
+ ret_value = ret_val; \
+ goto done; \
}
-/* HGOTO_DONE macro, used to facilitate the new error reporting model.
- This macro is just a wrapper to set the return value and jump to the 'done'
- label. Also assumption of a variable 'ret_value' */
+/*
+ * HGOTO_DONE macro, used to facilitate normal return between a FUNC_ENTER()
+ * and a FUNC_LEAVE() within a function body. The argument is the return
+ * value which is assigned to the `ret_value' variable. Control branches to
+ * the `done' label.
+ */
#define HGOTO_DONE(ret_val) {ret_value = ret_val; goto done;}
-/* H5ECLEAR macro, used to facilitate the new error reporting model.
- This macro is just a wrapper to clear the error stack with the thread
- error ID */
-#define H5ECLEAR H5Eclear(H5E_thrdid_g)
-
-/* Maximum length of function name to push onto error stack */
-#define MAX_FUNC_NAME 32
-
/*
- * error_messages is the list of error messages in the system, kept as
- * error_code-message pairs.
+ * The list of error messages in the system is kept as an array of
+ * error_code/message pairs, one for major error numbers and another for
+ * minor error numbers.
*/
typedef struct H5E_major_mesg_t {
H5E_major_t error_code;
- const char *str;
+ const char *str;
} H5E_major_mesg_t;
typedef struct H5E_minor_mesg_t {
H5E_minor_t error_code;
- const char *str;
+ const char *str;
} H5E_minor_mesg_t;
-/* Function pointer to report errors through */
-struct H5E_t; /*forward decl */
-typedef herr_t (*H5E_push_t)(struct H5E_t *estack, H5E_major_t maj_num,
- H5E_minor_t min_num, const char *function_name,
- const char *file_name, intn line,
- const char *desc);
-
-/*
- * We use a stack to hold the errors plus we keep track of the function, file
- * and line where the error occurs.
- */
-
-/* the structure of the error stack element */
-typedef struct H5E_error_t {
- H5E_major_t maj_num; /*major error number */
- H5E_minor_t min_num; /*minor error number */
- char func_name[MAX_FUNC_NAME]; /*function where error occur */
- const char *file_name; /*file where error occur */
- intn line; /*line in file where error occurs */
- char *desc; /*optional supplied description */
-} H5E_error_t;
-
-/* Structure to store error information for a thread */
+/* An error stack */
typedef struct H5E_t {
- uintn nelmts; /*num elements allocated in the stack */
- uintn top; /*index of the next open stack element */
- H5E_error_t *stack; /*pointer to the error stack */
- H5E_push_t push; /*func that pushes new error on stack */
+ uintn nused; /*num slots currently used in stack */
+ H5E_error_t slot[H5E_NSLOTS]; /*array of error records */
} H5E_t;
-/* Private global variables in H5E.c */
-extern hid_t H5E_thrdid_g; /* Thread-specific "global" error-handler ID */
-extern hbool_t install_atexit; /* Whether to install the atexit routine */
-extern const hbool_t H5E_clearable_g; /* Safe to call H5Eclear() on enter?*/
-
-herr_t H5E_close (H5E_t *estack);
-herr_t H5E_clear (H5E_t *estack);
-herr_t H5E_print (H5E_t *estack, FILE * file);
-herr_t H5E_push (H5E_t *estack, H5E_major_t maj_num, H5E_minor_t min_num,
- const char *function_name, const char *file_name, intn line,
- const char *desc);
+extern const hbool_t H5E_clearable_g; /*safe to call H5E_clear() on enter? */
+extern herr_t (*H5E_auto_g)(void *client_data);
+extern void *H5E_auto_data_g;
+
+herr_t H5E_push (H5E_major_t maj_num, H5E_minor_t min_num,
+ const char *func_name, const char *file_name, unsigned line,
+ const char *desc);
+herr_t H5E_clear (void);
+herr_t H5E_walk (H5E_direction_t dir, H5E_walk_t func, void *client_data);
+
+
#endif
diff --git a/src/H5Epublic.h b/src/H5Epublic.h
index c71bd3a..2ceb9a3 100644
--- a/src/H5Epublic.h
+++ b/src/H5Epublic.h
@@ -79,7 +79,7 @@ typedef enum H5E_minor_t {
H5E_OVERFLOW, /*address overflowed */
/* Function entry/exit interface errors */
- H5E_CANTINIT, /*Can't initialize interface */
+ H5E_CANTINIT, /*Can't initialize */
H5E_ALREADYINIT, /*object already initialized */
/* Object atom related errors */
@@ -114,17 +114,37 @@ typedef enum H5E_minor_t {
H5E_LINK /*link count failure */
} H5E_minor_t;
+/* Information about an error */
+typedef struct H5E_error_t {
+ H5E_major_t maj_num; /*major error number */
+ H5E_minor_t min_num; /*minor error number */
+ const char *func_name; /*function in which error occurred */
+ const char *file_name; /*file in which error occurred */
+ unsigned line; /*line in file where error occurs */
+ const char *desc; /*optional supplied description */
+} H5E_error_t;
+
+/* Error stack traversal direction */
+typedef enum H5E_direction_t {
+ H5E_WALK_UPWARD = 0, /*begin deep, end at API function */
+ H5E_WALK_DOWNWARD = 1 /*begin at API function, end deep */
+} H5E_direction_t;
+
+/* Error stack traversal callback function */
+typedef herr_t (*H5E_walk_t)(int n, H5E_error_t *err_desc, void *client_data);
+
#ifdef __cplusplus
extern "C" {
#endif
-hid_t H5Ecreate (uintn initial_stack_nelmts);
-herr_t H5Eclose (hid_t estack_id);
-herr_t H5Epush (hid_t estack_id, H5E_major_t maj_num, H5E_minor_t min_num,
- const char *function_name, const char *file_name, intn line,
- const char *desc);
-herr_t H5Eclear (hid_t estack_id);
-herr_t H5Eprint (hid_t estack_id, FILE * file);
+herr_t H5Eset_auto (herr_t (*func)(void*client_data), void *client_data);
+herr_t H5Eget_auto (herr_t (**func)(void*client_data), void **client_data);
+herr_t H5Eclear (void);
+herr_t H5Eprint (FILE *stream);
+herr_t H5Ewalk (H5E_direction_t direction, H5E_walk_t func, void *client_data);
+herr_t H5Ewalk_cb (int n, H5E_error_t *err_desc, void *client_data);
+const char *H5Eget_major (H5E_major_t major_number);
+const char *H5Eget_minor (H5E_minor_t minor_number);
#ifdef __cplusplus
}
diff --git a/src/H5G.c b/src/H5G.c
index e1212b0..82d00f3 100644
--- a/src/H5G.c
+++ b/src/H5G.c
@@ -710,7 +710,7 @@ H5G_mkroot(H5F_t *f, size_t size_hint)
* but the old root object is no longer the root object.
*/
H5O_remove(f->shared->root_ent, H5O_NAME, H5O_ALL);
- H5ECLEAR; /*who really cares? */
+ H5E_clear(); /*who really cares? */
*(f->shared->root_ent) = new_root;
@@ -777,13 +777,13 @@ H5G_create(H5F_t *f, const char *name, size_t size_hint)
if ((status = H5G_mkroot(f, H5G_SIZE_HINT)) < 0 && -2 != status) {
HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, NULL, "can't create root group");
}
- H5ECLEAR;
+ H5E_clear();
/* lookup name */
if (0 == H5G_namei(f, NULL, name, &rest, &grp_ent, NULL)) {
HRETURN_ERROR(H5E_SYM, H5E_EXISTS, NULL, "already exists");
}
- H5ECLEAR; /*it's OK that we didn't find it */
+ H5E_clear(); /*it's OK that we didn't find it */
assert(H5F_addr_defined(&(grp_ent.header)));
/* should be one null-terminated component left */
@@ -1155,7 +1155,7 @@ H5G_insert(const char *name, H5G_entry_t *ent)
if (H5G_namei(ent->file, NULL, name, &rest, &grp, NULL) >= 0) {
HRETURN_ERROR(H5E_SYM, H5E_EXISTS, FAIL, "already exists");
}
- H5ECLEAR; /*it's OK that we didn't find it */
+ H5E_clear(); /*it's OK that we didn't find it */
rest = H5G_component(rest, &nchars);
if (!rest || !*rest) {
@@ -1217,7 +1217,7 @@ H5G_insert(const char *name, H5G_entry_t *ent)
if ((status = H5G_mkroot(ent->file, H5G_SIZE_HINT)) < 0 && -2 != status) {
HRETURN_ERROR(H5E_SYM, H5E_CANTINIT, FAIL, "can't create root group");
}
- H5ECLEAR;
+ H5E_clear();
if (update_grp==TRUE)
grp = *(ent->file->shared->root_ent);
diff --git a/src/H5Gnode.c b/src/H5Gnode.c
index d309d97..390ea7d 100644
--- a/src/H5Gnode.c
+++ b/src/H5Gnode.c
@@ -957,7 +957,7 @@ H5G_node_debug(H5F_t *f, const haddr_t *addr, FILE * stream, intn indent,
* B-tree node.
*/
if (NULL == (sn = H5AC_protect(f, H5AC_SNODE, addr, NULL, NULL))) {
- H5ECLEAR; /*discard that error */
+ H5E_clear(); /*discard that error */
status = H5B_debug(f, addr, stream, indent, fwidth, H5B_SNODE, NULL);
if (status < 0) {
HRETURN_ERROR(H5E_SYM, H5E_CANTLOAD, FAIL,
diff --git a/src/H5H.c b/src/H5H.c
index 244d49c..54e537a 100644
--- a/src/H5H.c
+++ b/src/H5H.c
@@ -310,7 +310,7 @@ H5H_flush(H5F_t *f, hbool_t destroy, const haddr_t *addr, H5H_t *heap)
}
heap->addr = new_addr;
H5MF_free(f, &old_addr, heap->disk_alloc);
- H5ECLEAR; /*don't really care if the free failed */
+ H5E_clear(); /*don't really care if the free failed */
heap->disk_alloc = heap->mem_alloc;
}
diff --git a/src/H5O.c b/src/H5O.c
index 5f21eb4..06f61da 100644
--- a/src/H5O.c
+++ b/src/H5O.c
@@ -755,7 +755,7 @@ H5O_read(H5G_entry_t *ent, const H5O_class_t *type, intn sequence, void *mesg)
retval = (H5O_fast_g[cache_type]) (cache, type, mesg);
if (retval)
HRETURN(retval);
- H5ECLEAR; /*don't care, try reading from header */
+ H5E_clear(); /*don't care, try reading from header */
}
/* can we get it from the object header? */
@@ -1393,7 +1393,7 @@ H5O_alloc(H5F_t *f, H5O_t *oh, const H5O_class_t *type, size_t size)
if ((idx = H5O_alloc_extend_chunk(oh, chunkno, size)) >= 0) {
break;
}
- H5ECLEAR;
+ H5E_clear();
}
/*
diff --git a/src/H5T.c b/src/H5T.c
index e932e0f..d7fca16 100644
--- a/src/H5T.c
+++ b/src/H5T.c
@@ -289,7 +289,7 @@ H5T_term_interface(void)
fprintf (stderr, "HDF5-DIAG: conversion function failed "
"to free private data\n");
#endif
- H5ECLEAR; /*ignore the error*/
+ H5E_clear(); /*ignore the error*/
}
}
}
@@ -2221,7 +2221,7 @@ H5Tregister_soft(H5T_class_t src_cls, H5T_class_t dst_cls, H5T_conv_t func)
fprintf (stderr, "HDF5-DIAG: conversion function failed "
"to free private data.\n");
#endif
- H5ECLEAR;
+ H5E_clear();
}
}
path->func = func;
@@ -2231,7 +2231,7 @@ H5Tregister_soft(H5T_class_t src_cls, H5T_class_t dst_cls, H5T_conv_t func)
/* Release temporary atoms */
H5A_dec_ref(src_id);
H5A_dec_ref(dst_id);
- H5ECLEAR;
+ H5E_clear();
}
FUNC_LEAVE(SUCCEED);
@@ -2293,7 +2293,7 @@ H5Tunregister(H5T_conv_t func)
fprintf (stderr, "HDF5-DIAG: conversion function failed to "
"free private data.\n");
#endif
- H5ECLEAR;
+ H5E_clear();
}
HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t));
@@ -2324,7 +2324,7 @@ H5Tunregister(H5T_conv_t func)
0, NULL, NULL) >= 0) {
path->func = H5T_soft_g[j].func;
} else {
- H5ECLEAR;
+ H5E_clear();
HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t));
}
H5A_dec_ref(src_id);
@@ -3157,7 +3157,7 @@ H5T_path_find(const H5T_t *src, const H5T_t *dst, hbool_t create,
fprintf (stderr, "HDF5-DIAG: conversion function init "
"failed\n");
#endif
- H5ECLEAR; /*ignore the failure*/
+ H5E_clear(); /*ignore the failure*/
}
H5A_dec_ref(src_id);
H5A_dec_ref(dst_id);
@@ -3179,7 +3179,7 @@ H5T_path_find(const H5T_t *src, const H5T_t *dst, hbool_t create,
if ((H5T_soft_g[i].func) (src_id, dst_id, &(path->cdata),
H5T_CONV_INIT, NULL, NULL) < 0) {
HDmemset (&(path->cdata), 0, sizeof(H5T_cdata_t));
- H5ECLEAR; /*ignore the error*/
+ H5E_clear(); /*ignore the error*/
} else {
path->func = H5T_soft_g[i].func;
}
diff --git a/src/H5private.h b/src/H5private.h
index 1fc944b..49437cc 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -421,11 +421,15 @@ extern char *strdup(const char *s);
extern hbool_t library_initialize_g; /*good thing C's lazy about extern! */
extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */
-#define PRINT(N,S) { \
+/* Print S on file N followed by a newline */
+#define H5_PRINT(N,S) { \
write ((N), (S), strlen((S))); \
write ((N), "\n", 1); \
}
+/* Is `S' the name of an API function? */
+#define H5_IS_API(S) ('_'!=S[2] && '_'!=S[3] && (!S[4] || '_'!=S[4]))
+
#define FUNC_ENTER(func_name,err) FUNC_ENTER_INIT(func_name,INTERFACE_INIT,err)
#define FUNC_ENTER_INIT(func_name,interface_init_func,err) { \
@@ -463,10 +467,9 @@ extern hbool_t thread_initialize_g; /*don't decl interface_initialize_g */
} \
\
/* Clear thread error stack entering public functions */ \
- if (H5E_clearable_g && '_'!=FUNC[2] && '_'!=FUNC[3] && \
- (!FUNC[4] || '_'!=FUNC[4])) { \
- PRINT (55, #func_name); \
- H5Eclear (H5E_thrdid_g); \
+ if (H5E_clearable_g && H5_IS_API (FUNC)) { \
+ H5_PRINT (55, #func_name); \
+ H5E_clear (); \
} \
{
diff --git a/src/Makefile.in b/src/Makefile.in
index c9e4f55..e15b98e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -16,12 +16,12 @@ PROGS=debug
# Source and object files for the library (lexicographically)...
PARALLEL_SRC=H5Fmpio.c
-LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5P.c H5D.c H5E.c H5F.c H5Farray.c H5Fcore.c \
+LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5D.c H5E.c H5F.c H5Farray.c H5Fcore.c \
H5Ffamily.c H5Fistore.c H5Flow.c H5Fsec2.c H5Fsplit.c H5Fstdio.c \
H5G.c H5Gent.c H5Gnode.c H5Gstab.c H5H.c H5M.c H5MF.c H5MM.c H5O.c \
H5Ocont.c H5Odtype.c H5Oefl.c H5Olayout.c H5Oname.c H5Onull.c \
- H5Osdspace.c H5Ostab.c H5S.c H5Ssimp.c H5T.c H5Tconv.c H5Tinit.c \
- H5V.c @PARALLEL_SRC@
+ H5Osdspace.c H5Ostab.c H5P.c H5S.c H5Ssimp.c H5T.c H5Tconv.c \
+ H5Tinit.c H5V.c @PARALLEL_SRC@
LIB_OBJ=$(LIB_SRC:.c=.o)
diff --git a/test/dsets.c b/test/dsets.c
index 5d05288..8b373b0 100644
--- a/test/dsets.c
+++ b/test/dsets.c
@@ -11,11 +11,9 @@
#include <hdf5.h>
#include <math.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
-#include <H5Eprivate.h>
-
-
#ifndef HAVE_FUNCTION
#undef __FUNCTION__
#define __FUNCTION__ ""
@@ -83,12 +81,16 @@ test_create(hid_t file)
}
goto error;
}
+
/*
* Try creating a dataset that already exists. This should fail since a
- * dataset can only be created once.
+ * dataset can only be created once. Temporarily turn off error
+ * reporting.
*/
+ H5Eset_auto (NULL, NULL);
dataset = H5Dcreate(file, DSET_DEFAULT_NAME, H5T_NATIVE_DOUBLE, space,
H5P_DEFAULT);
+ H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout);
if (dataset >= 0) {
puts("*FAILED*");
if (!isatty(1)) {
@@ -97,6 +99,7 @@ test_create(hid_t file)
}
goto error;
}
+
/*
* Open the dataset we created above and then close it. This is how
* existing datasets are accessed.
@@ -118,11 +121,15 @@ test_create(hid_t file)
}
goto error;
}
+
/*
* Try opening a non-existent dataset. This should fail since new datasets
- * cannot be created with this function.
+ * cannot be created with this function. Temporarily turn off error
+ * reporting.
*/
+ H5Eset_auto (NULL, NULL);
dataset = H5Dopen(file, "does_not_exist");
+ H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout);
if (dataset >= 0) {
puts("*FAILED*");
if (!isatty(1)) {
@@ -312,7 +319,6 @@ test_tconv(hid_t file)
/* Write the data to the dataset */
status = H5Dwrite(dataset, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL,
H5P_DEFAULT, out);
- if (status<0) H5Eprint (H5E_thrdid_g, stdout);
assert(status >= 0);
/* Create a new type with the opposite byte order */
@@ -374,6 +380,9 @@ main(void)
status = H5open ();
assert (status>=0);
+ /* Automatic error reporting to standard output */
+ H5Eset_auto ((herr_t(*)(void*))H5Eprint, stdout);
+
unlink("dataset.h5");
file = H5Fcreate("dataset.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
assert(file >= 0);
diff --git a/test/testhdf5.c b/test/testhdf5.c
index b122606..40abfb5 100644
--- a/test/testhdf5.c
+++ b/test/testhdf5.c
@@ -152,6 +152,13 @@ main(int argc, char *argv[])
setbuf(stdout, NULL);
#endif
+ /*
+ * Turn off automatic error reporting since we do it ourselves. Besides,
+ * half the functions this test calls are private, so automatic error
+ * reporting wouldn't do much good since it's triggered at the API layer.
+ */
+ H5Eset_auto (NULL, NULL);
+
/* Tests are generally arranged from least to most complexity... */
InitTest("metadata", test_metadata, "Encode/decode metadata code");
InitTest("file", test_file, "Low-Level File I/O");
diff --git a/test/testhdf5.h b/test/testhdf5.h
index ed9e0a3..0288880 100644
--- a/test/testhdf5.h
+++ b/test/testhdf5.h
@@ -31,51 +31,77 @@ extern int Verbosity;
/* Use %ld to print the value because long should cover most cases. */
/* Used to make certain a return value _is_not_ a value */
-#define CHECK(ret, val, where) \
-do {if (Verbosity>9) print_func(" Call to routine: %15s at line %4d in %s returned %ld \n",where,(int)__LINE__,__FILE__,(long)ret);\
-if(ret == val) {print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d in %s\n", where, (long)ret, (int)__LINE__,__FILE__); num_errs++;H5Eprint (H5E_thrdid_g, stdout);} H5Eclear(H5E_thrdid_g);\
+#define CHECK(ret, val, where) do { \
+ if (Verbosity>9) print_func(" Call to routine: %15s at line %4d " \
+ "in %s returned %ld \n", \
+ where, (int)__LINE__, __FILE__, \
+ (long)ret); \
+ if (ret == val) { \
+ print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d " \
+ "in %s\n", where, (long)ret, (int)__LINE__, __FILE__); \
+ num_errs++; \
+ H5Eprint (stdout); \
+ } \
+ H5Eclear(); \
} while(0)
-#define CHECK_I(ret,where) { \
- if (Verbosity>9) { \
+#define CHECK_I(ret,where) { \
+ if (Verbosity>9) { \
print_func(" Call to routine: %15s at line %4d in %s returned %ld\n", \
- (where), (int)__LINE__, __FILE__, (long)(ret)); \
- } \
- if ((ret)<0) { \
+ (where), (int)__LINE__, __FILE__, (long)(ret)); \
+ } \
+ if ((ret)<0) { \
print_func ("*** UNEXPECTED RETURN from %s is %ld line %4d in %s\n", \
- (where), (long)(ret), (int)__LINE__, __FILE__); \
- H5Eprint (H5E_thrdid_g, stdout); \
- num_errs++; \
- } \
- H5Eclear (H5E_thrdid_g); \
+ (where), (long)(ret), (int)__LINE__, __FILE__); \
+ H5Eprint (stdout); \
+ num_errs++; \
+ } \
+ H5Eclear (); \
}
-#define CHECK_PTR(ret,where) { \
- if (Verbosity>9) { \
+#define CHECK_PTR(ret,where) { \
+ if (Verbosity>9) { \
print_func(" Call to routine: %15s at line %4d in %s returned %p\n", \
- (where), (int)__LINE__, __FILE__, (ret)); \
- } \
- if (!(ret)) { \
+ (where), (int)__LINE__, __FILE__, (ret)); \
+ } \
+ if (!(ret)) { \
print_func ("*** UNEXPECTED RETURN from %s is NULL line %4d in %s\n", \
- (where), (int)__LINE__, __FILE__); \
- H5Eprint (H5E_thrdid_g, stdout); \
- num_errs++; \
- } \
- H5Eclear (H5E_thrdid_g); \
+ (where), (int)__LINE__, __FILE__); \
+ H5Eprint (stdout); \
+ num_errs++; \
+ } \
+ H5Eclear (); \
}
/* Used to make certain a return value _is_ a value */
-#define VERIFY(x, val, where) \
-do {if (Verbosity>9) print_func(" Call to routine: %15s at line %4d in %s had value %ld \n",where,(int)__LINE__,__FILE__,(long)x);\
-if(x != val) {print_func("*** UNEXPECTED VALUE from %s is %ld at line %4d in %s\n", where, (long)x,(int)__LINE__,__FILE__); H5Eprint (H5E_thrdid_g, stdout);num_errs++;}H5Eclear(H5E_thrdid_g); \
+#define VERIFY(x, val, where) do { \
+ if (Verbosity>9) { \
+ print_func(" Call to routine: %15s at line %4d in %s had value " \
+ "%ld \n", where, (int)__LINE__, __FILE__, (long)x); \
+ } \
+ if (x != val) { \
+ print_func("*** UNEXPECTED VALUE from %s is %ld at line %4d " \
+ "in %s\n", where, (long)x, (int)__LINE__, __FILE__); \
+ H5Eprint (stdout); \
+ num_errs++; \
+ } \
+ H5Eclear(); \
} while(0)
/* Used to document process through a test and to check for errors */
-#define RESULT(ret,func) \
-do { \
-if (Verbosity>8) print_func(" Call to routine: %15s at line %4d in %s returned %ld \n",func,(int)__LINE__,__FILE__,(long)ret); \
-if (Verbosity>9) HEprint(stdout,0); \
-if(ret == FAIL) {print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d in %s\n", func, (long)ret,(int)__LINE__,__FILE__); H5Eprint (H5E_thrdid_g, stdout); num_errs++;} H5Eclear(H5E_thrdid_g);\
+#define RESULT(ret,func) do { \
+ if (Verbosity>8) { \
+ print_func(" Call to routine: %15s at line %4d in %s returned " \
+ "%ld\n", func, (int)__LINE__, __FILE__, (long)ret); \
+ } \
+ if (Verbosity>9) HEprint(stdout, 0); \
+ if (ret == FAIL) { \
+ print_func("*** UNEXPECTED RETURN from %s is %ld at line %4d " \
+ "in %s\n", func, (long)ret, (int)__LINE__, __FILE__); \
+ H5Eprint (stdout); \
+ num_errs++; \
+ } \
+ H5Eclear(); \
} while(0)
/* Used to document process through a test */