diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | src/H5.c | 9 | ||||
-rw-r--r-- | src/H5Apublic.h | 3 | ||||
-rw-r--r-- | src/H5E.c | 941 | ||||
-rw-r--r-- | src/H5Eprivate.h | 169 | ||||
-rw-r--r-- | src/H5Epublic.h | 36 | ||||
-rw-r--r-- | src/H5G.c | 10 | ||||
-rw-r--r-- | src/H5Gnode.c | 2 | ||||
-rw-r--r-- | src/H5H.c | 2 | ||||
-rw-r--r-- | src/H5O.c | 4 | ||||
-rw-r--r-- | src/H5T.c | 14 | ||||
-rw-r--r-- | src/H5private.h | 13 | ||||
-rw-r--r-- | src/Makefile.in | 6 | ||||
-rw-r--r-- | test/dsets.c | 21 | ||||
-rw-r--r-- | test/testhdf5.c | 7 | ||||
-rw-r--r-- | test/testhdf5.h | 88 |
16 files changed, 675 insertions, 651 deletions
@@ -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 @@ -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 */ @@ -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 } @@ -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, @@ -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; } @@ -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(); } /* @@ -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 */ |