mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
89fbe00dec
* commit '54957d37f5aa73912763dbb6e308555e863c43f4': Commit copyright header change for src/H5PLpkg.c which was added after running script to make changes. Add new files in release_docs to MANIFEST. Cimmit changes to Makefile.in(s) and H5PL.c that resulted from running autogen.sh. Merge pull request #407 in HDFFV/hdf5 from ~LRKNOX/hdf5_lrk:hdf5_1_10_1 to hdf5_1_10_1 Change copyright headers to replace url referring to file to be removed and replace it with new url for COPYING file.
1017 lines
34 KiB
C
1017 lines
34 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by The HDF Group. *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* All rights reserved. *
|
||
* *
|
||
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
||
* terms governing use, modification, and redistribution, is contained in *
|
||
* the COPYING file, which can be found at the root of the source code *
|
||
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
|
||
* If you do not have access to either file, you may request a copy from *
|
||
* help@hdfgroup.org. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/*-------------------------------------------------------------------------
|
||
*
|
||
* Created: H5Eint.c
|
||
* April 11 2007
|
||
* Quincey Koziol <koziol@hdfgroup.org>
|
||
*
|
||
* Purpose: General use, "internal" routines for error handling.
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
|
||
/****************/
|
||
/* Module Setup */
|
||
/****************/
|
||
|
||
#include "H5Emodule.h" /* This source code file is part of the H5E module */
|
||
|
||
|
||
/***********/
|
||
/* Headers */
|
||
/***********/
|
||
#include "H5private.h" /* Generic Functions */
|
||
#include "H5Epkg.h" /* Error handling */
|
||
#include "H5Iprivate.h" /* IDs */
|
||
#include "H5MMprivate.h" /* Memory management */
|
||
|
||
|
||
/****************/
|
||
/* Local Macros */
|
||
/****************/
|
||
|
||
|
||
/******************/
|
||
/* Local Typedefs */
|
||
/******************/
|
||
|
||
/* Printing information */
|
||
typedef struct H5E_print_t {
|
||
FILE *stream;
|
||
H5E_cls_t cls;
|
||
} H5E_print_t;
|
||
|
||
|
||
/********************/
|
||
/* Package Typedefs */
|
||
/********************/
|
||
|
||
|
||
/********************/
|
||
/* Local Prototypes */
|
||
/********************/
|
||
#ifndef H5_NO_DEPRECATED_SYMBOLS
|
||
static herr_t H5E_walk1_cb(int n, H5E_error1_t *err_desc,
|
||
void *client_data);
|
||
#endif /* H5_NO_DEPRECATED_SYMBOLS */
|
||
static herr_t H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc,
|
||
void *client_data);
|
||
static herr_t H5E_clear_entries(H5E_t *estack, size_t nentries);
|
||
|
||
|
||
/*********************/
|
||
/* Package Variables */
|
||
/*********************/
|
||
|
||
#ifndef H5_HAVE_THREADSAFE
|
||
/*
|
||
* The current error stack.
|
||
*/
|
||
H5E_t H5E_stack_g[1];
|
||
#endif /* H5_HAVE_THREADSAFE */
|
||
|
||
|
||
/*****************************/
|
||
/* Library Private Variables */
|
||
/*****************************/
|
||
|
||
/* HDF5 error class ID */
|
||
hid_t H5E_ERR_CLS_g = FAIL;
|
||
|
||
/*
|
||
* Predefined errors. These are initialized at runtime in H5E_init_interface()
|
||
* in this source file.
|
||
*/
|
||
/* Include the automatically generated error code definitions */
|
||
#include "H5Edefin.h"
|
||
|
||
|
||
/*******************/
|
||
/* Local Variables */
|
||
/*******************/
|
||
|
||
#ifdef H5_HAVE_PARALLEL
|
||
/*
|
||
* variables used for MPI error reporting
|
||
*/
|
||
char H5E_mpi_error_str[MPI_MAX_ERROR_STRING];
|
||
int H5E_mpi_error_str_len;
|
||
#endif /* H5_HAVE_PARALLEL */
|
||
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_get_msg
|
||
*
|
||
* Purpose: Private function to retrieve an error message.
|
||
*
|
||
* Return: Non-negative for name length if succeeds(zero means no name);
|
||
* otherwise returns negative value.
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Friday, July 14, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
ssize_t
|
||
H5E_get_msg(const H5E_msg_t *msg, H5E_type_t *type, char *msg_str, size_t size)
|
||
{
|
||
ssize_t len = -1; /* Length of error message */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
/* Check arguments */
|
||
HDassert(msg);
|
||
|
||
/* Get the length of the message string */
|
||
len = (ssize_t)HDstrlen(msg->msg);
|
||
|
||
/* Copy the message into the user's buffer, if given */
|
||
if(msg_str) {
|
||
HDstrncpy(msg_str, msg->msg, MIN((size_t)(len+1), size));
|
||
if((size_t)len >= size)
|
||
msg_str[size - 1] = '\0';
|
||
} /* end if */
|
||
|
||
/* Give the message type, if asked */
|
||
if(type)
|
||
*type = msg->type;
|
||
|
||
/* Set the return value to the full length of the message */
|
||
FUNC_LEAVE_NOAPI(len)
|
||
} /* end H5E_get_msg() */
|
||
|
||
#ifndef H5_NO_DEPRECATED_SYMBOLS
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_walk1_cb
|
||
*
|
||
* Purpose: This function is for backward compatibility.
|
||
* This is a default error stack traversal callback function
|
||
* that prints error messages to the specified output stream.
|
||
* This function is for backward compatibility with v1.6.
|
||
* 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.
|
||
*
|
||
* 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).
|
||
*
|
||
* ERR_DESC is an error description. It contains all the
|
||
* information about a particular error.
|
||
*
|
||
* 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: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Thursday, May 11, 2006
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5E_walk1_cb(int n, H5E_error1_t *err_desc, void *client_data)
|
||
{
|
||
H5E_print_t *eprint = (H5E_print_t *)client_data;
|
||
FILE *stream; /* I/O stream to print output to */
|
||
H5E_cls_t *cls_ptr; /* Pointer to error class */
|
||
H5E_msg_t *maj_ptr; /* Pointer to major error info */
|
||
H5E_msg_t *min_ptr; /* Pointer to minor error info */
|
||
const char *maj_str = "No major description"; /* Major error description */
|
||
const char *min_str = "No minor description"; /* Minor error description */
|
||
unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
/* Check arguments */
|
||
HDassert(err_desc);
|
||
|
||
/* If no client data was passed, output to stderr */
|
||
if(!client_data)
|
||
stream = stderr;
|
||
else
|
||
stream = eprint->stream;
|
||
|
||
/* Get descriptions for the major and minor error numbers */
|
||
maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
|
||
min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
|
||
|
||
/* Check for bad pointer(s), but can't issue error, just leave */
|
||
if(!maj_ptr || !min_ptr)
|
||
HGOTO_DONE(FAIL)
|
||
|
||
if(maj_ptr->msg)
|
||
maj_str = maj_ptr->msg;
|
||
if(min_ptr->msg)
|
||
min_str = min_ptr->msg;
|
||
|
||
/* Get error class info */
|
||
cls_ptr = maj_ptr->cls;
|
||
|
||
/* Print error class header if new class */
|
||
if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
|
||
/* update to the new class information */
|
||
if(cls_ptr->cls_name)
|
||
eprint->cls.cls_name = cls_ptr->cls_name;
|
||
if(cls_ptr->lib_name)
|
||
eprint->cls.lib_name = cls_ptr->lib_name;
|
||
if(cls_ptr->lib_vers)
|
||
eprint->cls.lib_vers = cls_ptr->lib_vers;
|
||
|
||
fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
|
||
(cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
|
||
(cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
|
||
(cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
|
||
|
||
/* try show the process or thread id in multiple processes cases*/
|
||
#ifdef H5_HAVE_PARALLEL
|
||
{
|
||
int mpi_rank, mpi_initialized, mpi_finalized;
|
||
|
||
MPI_Initialized(&mpi_initialized);
|
||
MPI_Finalized(&mpi_finalized);
|
||
|
||
if(mpi_initialized && !mpi_finalized) {
|
||
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
|
||
fprintf(stream, "MPI-process %d", mpi_rank);
|
||
} /* end if */
|
||
else
|
||
fprintf(stream, "thread 0");
|
||
} /* end block */
|
||
#elif defined(H5_HAVE_THREADSAFE)
|
||
fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
|
||
#else
|
||
fprintf(stream, "thread 0");
|
||
#endif
|
||
fprintf(stream, ":\n");
|
||
} /* end if */
|
||
|
||
/* Check for "real" error description - used to format output more nicely */
|
||
if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
|
||
have_desc=0;
|
||
|
||
/* Print error message */
|
||
fprintf(stream, "%*s#%03d: %s line %u in %s()%s%s\n",
|
||
H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
|
||
err_desc->func_name, (have_desc ? ": " : ""),
|
||
(have_desc ? err_desc->desc : ""));
|
||
fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
|
||
fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_walk1_cb() */
|
||
#endif /* H5_NO_DEPRECATED_SYMBOLS */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_walk2_cb
|
||
*
|
||
* 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 H5Ewalk2() function. This function is
|
||
* called also by H5Eprint2(). Application writers are
|
||
* encouraged to use this function as a model for their own
|
||
* error stack walking functions.
|
||
*
|
||
* 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).
|
||
*
|
||
* ERR_DESC is an error description. It contains all the
|
||
* information about a particular error.
|
||
*
|
||
* 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: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, December 12, 1997
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data)
|
||
{
|
||
H5E_print_t *eprint = (H5E_print_t *)client_data;
|
||
FILE *stream; /* I/O stream to print output to */
|
||
H5E_cls_t *cls_ptr; /* Pointer to error class */
|
||
H5E_msg_t *maj_ptr; /* Pointer to major error info */
|
||
H5E_msg_t *min_ptr; /* Pointer to minor error info */
|
||
const char *maj_str = "No major description"; /* Major error description */
|
||
const char *min_str = "No minor description"; /* Minor error description */
|
||
unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
/* Check arguments */
|
||
HDassert(err_desc);
|
||
|
||
/* If no client data was passed, output to stderr */
|
||
if(!client_data)
|
||
stream = stderr;
|
||
else
|
||
stream = eprint->stream;
|
||
|
||
/* Get descriptions for the major and minor error numbers */
|
||
maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
|
||
min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
|
||
|
||
/* Check for bad pointer(s), but can't issue error, just leave */
|
||
if(!maj_ptr || !min_ptr)
|
||
HGOTO_DONE(FAIL)
|
||
|
||
if(maj_ptr->msg)
|
||
maj_str = maj_ptr->msg;
|
||
if(min_ptr->msg)
|
||
min_str = min_ptr->msg;
|
||
|
||
/* Get error class info. Don't use the class of the major or minor error because
|
||
* they might be different. */
|
||
cls_ptr = (H5E_cls_t *)H5I_object_verify(err_desc->cls_id, H5I_ERROR_CLASS);
|
||
|
||
/* Check for bad pointer(s), but can't issue error, just leave */
|
||
if(!cls_ptr)
|
||
HGOTO_DONE(FAIL)
|
||
|
||
/* Print error class header if new class */
|
||
if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
|
||
/* update to the new class information */
|
||
if(cls_ptr->cls_name)
|
||
eprint->cls.cls_name = cls_ptr->cls_name;
|
||
if(cls_ptr->lib_name)
|
||
eprint->cls.lib_name = cls_ptr->lib_name;
|
||
if(cls_ptr->lib_vers)
|
||
eprint->cls.lib_vers = cls_ptr->lib_vers;
|
||
|
||
fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
|
||
(cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
|
||
(cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
|
||
(cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
|
||
|
||
/* try show the process or thread id in multiple processes cases*/
|
||
#ifdef H5_HAVE_PARALLEL
|
||
{
|
||
int mpi_rank, mpi_initialized, mpi_finalized;
|
||
|
||
MPI_Initialized(&mpi_initialized);
|
||
MPI_Finalized(&mpi_finalized);
|
||
|
||
if(mpi_initialized && !mpi_finalized) {
|
||
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
|
||
fprintf(stream, "MPI-process %d", mpi_rank);
|
||
} /* end if */
|
||
else
|
||
fprintf(stream, "thread 0");
|
||
} /* end block */
|
||
#elif defined(H5_HAVE_THREADSAFE)
|
||
fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
|
||
#else
|
||
fprintf(stream, "thread 0");
|
||
#endif
|
||
fprintf(stream, ":\n");
|
||
} /* end if */
|
||
|
||
/* Check for "real" error description - used to format output more nicely */
|
||
if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
|
||
have_desc = 0;
|
||
|
||
/* Print error message */
|
||
fprintf(stream, "%*s#%03u: %s line %u in %s()%s%s\n",
|
||
H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
|
||
err_desc->func_name, (have_desc ? ": " : ""),
|
||
(have_desc ? err_desc->desc : ""));
|
||
fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
|
||
fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_walk2_cb() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_print
|
||
*
|
||
* Purpose: Private function to print the error stack in some default
|
||
* way. This is just a convenience function for H5Ewalk() and
|
||
* H5Ewalk2() with a function that prints error messages.
|
||
* Users are encouraged to write there own more specific error
|
||
* handlers.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, February 27, 1998
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_print(const H5E_t *estack, FILE *stream, hbool_t bk_compatible)
|
||
{
|
||
H5E_print_t eprint; /* Callback information to pass to H5E_walk() */
|
||
H5E_walk_op_t walk_op; /* Error stack walking callback */
|
||
herr_t ret_value = SUCCEED;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
/* Sanity check */
|
||
HDassert(estack);
|
||
|
||
/* If no stream was given, use stderr */
|
||
if(!stream)
|
||
eprint.stream = stderr;
|
||
else
|
||
eprint.stream = stream;
|
||
|
||
/* Reset the original error class information */
|
||
HDmemset(&eprint.cls, 0, sizeof(H5E_cls_t));
|
||
|
||
/* Walk the error stack */
|
||
if(bk_compatible) {
|
||
#ifndef H5_NO_DEPRECATED_SYMBOLS
|
||
walk_op.vers = 1;
|
||
walk_op.u.func1 = H5E_walk1_cb;
|
||
if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
|
||
#else /* H5_NO_DEPRECATED_SYMBOLS */
|
||
HDassert(0 && "version 1 error stack print without deprecated symbols!");
|
||
#endif /* H5_NO_DEPRECATED_SYMBOLS */
|
||
} /* end if */
|
||
else {
|
||
walk_op.vers = 2;
|
||
walk_op.u.func2 = H5E_walk2_cb;
|
||
if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
|
||
} /* end else */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_print() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_walk
|
||
*
|
||
* Purpose: Private function for H5Ewalk.
|
||
* 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.
|
||
*
|
||
* The function pointed to by STACK_FUNC will be called for
|
||
* each error record 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.
|
||
*
|
||
* The function FUNC is also provided for backward compatibility.
|
||
* When BK_COMPATIBLE is set to be TRUE, FUNC is used to be
|
||
* compatible with older library. If BK_COMPATIBLE is FALSE,
|
||
* STACK_FUNC is used.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, December 12, 1997
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_walk(const H5E_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op,
|
||
void *client_data)
|
||
{
|
||
int i; /* Local index variable */
|
||
herr_t status; /* Status from callback function */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
/* Sanity check */
|
||
HDassert(estack);
|
||
HDassert(op);
|
||
|
||
/* 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 if a callback function was given */
|
||
if(op->vers == 1) {
|
||
#ifndef H5_NO_DEPRECATED_SYMBOLS
|
||
if(op->u.func1) {
|
||
H5E_error1_t old_err;
|
||
|
||
status = SUCCEED;
|
||
if(H5E_WALK_UPWARD == direction) {
|
||
for(i = 0; i < (int)estack->nused && status >= 0; i++) {
|
||
/* Point to each error record on the stack and pass it to callback function.*/
|
||
old_err.maj_num = estack->slot[i].maj_num;
|
||
old_err.min_num = estack->slot[i].min_num;
|
||
old_err.func_name = estack->slot[i].func_name;
|
||
old_err.file_name = estack->slot[i].file_name;
|
||
old_err.desc = estack->slot[i].desc;
|
||
old_err.line = estack->slot[i].line;
|
||
|
||
status = (op->u.func1)(i, &old_err, client_data);
|
||
} /* end for */
|
||
} /* end if */
|
||
else {
|
||
H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
|
||
for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--) {
|
||
/* Point to each error record on the stack and pass it to callback function.*/
|
||
old_err.maj_num = estack->slot[i].maj_num;
|
||
old_err.min_num = estack->slot[i].min_num;
|
||
old_err.func_name = estack->slot[i].func_name;
|
||
old_err.file_name = estack->slot[i].file_name;
|
||
old_err.desc = estack->slot[i].desc;
|
||
old_err.line = estack->slot[i].line;
|
||
|
||
status = (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data);
|
||
} /* end for */
|
||
} /* end else */
|
||
|
||
if(status < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
|
||
} /* end if */
|
||
#else /* H5_NO_DEPRECATED_SYMBOLS */
|
||
HDassert(0 && "version 1 error stack walk without deprecated symbols!");
|
||
#endif /* H5_NO_DEPRECATED_SYMBOLS */
|
||
} /* end if */
|
||
else {
|
||
HDassert(op->vers == 2);
|
||
if(op->u.func2) {
|
||
status = SUCCEED;
|
||
if(H5E_WALK_UPWARD == direction) {
|
||
for(i = 0; i < (int)estack->nused && status >= 0; i++)
|
||
status = (op->u.func2)((unsigned)i, estack->slot + i, client_data);
|
||
} /* end if */
|
||
else {
|
||
H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
|
||
for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--)
|
||
status = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)), estack->slot + i, client_data);
|
||
} /* end else */
|
||
|
||
if(status < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
|
||
} /* end if */
|
||
} /* end else */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_walk() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_get_auto
|
||
*
|
||
* Purpose: Private function to return the current settings for the
|
||
* automatic error stack traversal function and its data
|
||
* for specific error stack. Either (or both) arguments may
|
||
* be null in which case the value is not returned.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* July 18, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_get_auto(const H5E_t *estack, H5E_auto_op_t *op, void **client_data)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
HDassert(estack);
|
||
|
||
/* Retrieve the requested information */
|
||
if(op)
|
||
*op = estack->auto_op;
|
||
if(client_data)
|
||
*client_data = estack->auto_data;
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* end H5E_get_auto2() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_set_auto
|
||
*
|
||
* Purpose: Private function to turn on or off automatic printing of
|
||
* errors for certain error stack. When turned on (non-null
|
||
* FUNC pointer) any API function which returns an error
|
||
* indication will first call FUNC passing it CLIENT_DATA
|
||
* as an argument.
|
||
*
|
||
* The default values before this function is called are
|
||
* H5Eprint2() with client data being the standard error stream,
|
||
* stderr.
|
||
*
|
||
* Automatic stack traversal is always in the H5E_WALK_DOWNWARD
|
||
* direction.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, February 27, 1998
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_set_auto(H5E_t *estack, const H5E_auto_op_t *op, void *client_data)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
HDassert(estack);
|
||
|
||
/* Set the automatic error reporting info */
|
||
estack->auto_op = *op;
|
||
estack->auto_data = client_data;
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* end H5E_set_auto() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_printf_stack
|
||
*
|
||
* Purpose: Printf-like wrapper around H5E_push_stack.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Tuesday, August 12, 2008
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
|
||
hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...)
|
||
{
|
||
va_list ap; /* Varargs info */
|
||
#ifndef H5_HAVE_VASPRINTF
|
||
int tmp_len; /* Current size of description buffer */
|
||
int desc_len; /* Actual length of description when formatted */
|
||
#endif /* H5_HAVE_VASPRINTF */
|
||
char *tmp = NULL; /* Buffer to place formatted description in */
|
||
hbool_t va_started = FALSE; /* Whether the variable argument list is open */
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
/*
|
||
* 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().
|
||
*/
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
/* Sanity check */
|
||
HDassert(cls_id > 0);
|
||
HDassert(maj_id > 0);
|
||
HDassert(min_id > 0);
|
||
HDassert(fmt);
|
||
|
||
/* Note that the variable-argument parsing for the format is identical in
|
||
* the H5Epush2() routine - correct errors and make changes in both
|
||
* places. -QAK
|
||
*/
|
||
|
||
/* Start the variable-argument parsing */
|
||
va_start(ap, fmt);
|
||
va_started = TRUE;
|
||
|
||
#ifdef H5_HAVE_VASPRINTF
|
||
/* Use the vasprintf() routine, since it does what we're trying to do below */
|
||
if(HDvasprintf(&tmp, fmt, ap) < 0)
|
||
HGOTO_DONE(FAIL)
|
||
#else /* H5_HAVE_VASPRINTF */
|
||
/* Allocate space for the formatted description buffer */
|
||
tmp_len = 128;
|
||
if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
|
||
HGOTO_DONE(FAIL)
|
||
|
||
/* If the description doesn't fit into the initial buffer size, allocate more space and try again */
|
||
while((desc_len = HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) > (tmp_len - 1)) {
|
||
/* shutdown & restart the va_list */
|
||
va_end(ap);
|
||
va_start(ap, fmt);
|
||
|
||
/* Release the previous description, it's too small */
|
||
H5MM_xfree(tmp);
|
||
|
||
/* Allocate a description of the appropriate length */
|
||
tmp_len = desc_len + 1;
|
||
if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
|
||
HGOTO_DONE(FAIL)
|
||
} /* end while */
|
||
#endif /* H5_HAVE_VASPRINTF */
|
||
|
||
/* Push the error on the stack */
|
||
if(H5E_push_stack(estack, file, func, line, cls_id, maj_id, min_id, tmp) < 0)
|
||
HGOTO_DONE(FAIL)
|
||
|
||
done:
|
||
if(va_started)
|
||
va_end(ap);
|
||
#ifdef H5_HAVE_VASPRINTF
|
||
/* Memory was allocated with HDvasprintf so it needs to be freed
|
||
* with HDfree
|
||
*/
|
||
if(tmp)
|
||
HDfree(tmp);
|
||
#else /* H5_HAVE_VASPRINTF */
|
||
if(tmp)
|
||
H5MM_xfree(tmp);
|
||
#endif /* H5_HAVE_VASPRINTF */
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_printf_stack() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_push_stack
|
||
*
|
||
* Purpose: Pushes a new error record onto error stack for the current
|
||
* thread. The error has major and minor IDs MAJ_ID and
|
||
* MIN_ID, 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: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, December 12, 1997
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_push_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
|
||
hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc)
|
||
{
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
/*
|
||
* 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().
|
||
*/
|
||
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
||
|
||
/* Sanity check */
|
||
HDassert(cls_id > 0);
|
||
HDassert(maj_id > 0);
|
||
HDassert(min_id > 0);
|
||
|
||
/* Check for 'default' error stack */
|
||
if(estack == NULL)
|
||
if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
|
||
HGOTO_DONE(FAIL)
|
||
|
||
/*
|
||
* Don't fail if arguments are bad. Instead, substitute some default
|
||
* value.
|
||
*/
|
||
if(!func)
|
||
func = "Unknown_Function";
|
||
if(!file)
|
||
file = "Unknown_File";
|
||
if(!desc)
|
||
desc = "No description given";
|
||
|
||
/*
|
||
* Push the error if there's room. Otherwise just forget it.
|
||
*/
|
||
HDassert(estack);
|
||
|
||
if(estack->nused < H5E_NSLOTS) {
|
||
/* Increment the IDs to indicate that they are used in this stack */
|
||
if(H5I_inc_ref(cls_id, FALSE) < 0)
|
||
HGOTO_DONE(FAIL)
|
||
estack->slot[estack->nused].cls_id = cls_id;
|
||
if(H5I_inc_ref(maj_id, FALSE) < 0)
|
||
HGOTO_DONE(FAIL)
|
||
estack->slot[estack->nused].maj_num = maj_id;
|
||
if(H5I_inc_ref(min_id, FALSE) < 0)
|
||
HGOTO_DONE(FAIL)
|
||
estack->slot[estack->nused].min_num = min_id;
|
||
if(NULL == (estack->slot[estack->nused].func_name = H5MM_xstrdup(func)))
|
||
HGOTO_DONE(FAIL)
|
||
if(NULL == (estack->slot[estack->nused].file_name = H5MM_xstrdup(file)))
|
||
HGOTO_DONE(FAIL)
|
||
estack->slot[estack->nused].line = line;
|
||
if(NULL == (estack->slot[estack->nused].desc = H5MM_xstrdup(desc)))
|
||
HGOTO_DONE(FAIL)
|
||
estack->nused++;
|
||
} /* end if */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_push_stack() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_clear_entries
|
||
*
|
||
* Purpose: Private function to clear the error stack entries for the
|
||
* specified error stack.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Wednesday, August 6, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static herr_t
|
||
H5E_clear_entries(H5E_t *estack, size_t nentries)
|
||
{
|
||
H5E_error2_t *error; /* Pointer to error stack entry to clear */
|
||
unsigned u; /* Local index variable */
|
||
herr_t ret_value=SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
/* Sanity check */
|
||
HDassert(estack);
|
||
HDassert(estack->nused >= nentries);
|
||
|
||
/* Empty the error stack from the top down */
|
||
for(u = 0; nentries > 0; nentries--, u++) {
|
||
error = &(estack->slot[estack->nused - (u + 1)]);
|
||
|
||
/* Decrement the IDs to indicate that they are no longer used by this stack */
|
||
/* (In reverse order that they were incremented, so that reference counts work well) */
|
||
if(H5I_dec_ref(error->min_num) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
|
||
if(H5I_dec_ref(error->maj_num) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
|
||
if(H5I_dec_ref(error->cls_id) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error class")
|
||
|
||
/* Release strings */
|
||
if(error->func_name)
|
||
H5MM_xfree((void *)error->func_name); /* Casting away const OK - QAK */
|
||
if(error->file_name)
|
||
H5MM_xfree((void *)error->file_name); /* Casting away const OK - QAK */
|
||
if(error->desc)
|
||
H5MM_xfree((void *)error->desc); /* Casting away const OK - QAK */
|
||
} /* end for */
|
||
|
||
/* Decrement number of errors on stack */
|
||
estack->nused -= u;
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_clear_entries() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_clear_stack
|
||
*
|
||
* Purpose: Private function to clear the error stack for the
|
||
* specified error stack.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Wednesday, July 16, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_clear_stack(H5E_t *estack)
|
||
{
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(FAIL)
|
||
|
||
/* Check for 'default' error stack */
|
||
if(estack == NULL)
|
||
if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
|
||
|
||
/* Empty the error stack */
|
||
HDassert(estack);
|
||
if(estack->nused)
|
||
if(H5E_clear_entries(estack, estack->nused) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack")
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_clear_stack() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_pop
|
||
*
|
||
* Purpose: Private function to delete some error messages from the top
|
||
* of error stack.
|
||
*
|
||
* Return: Non-negative value on success/Negative on failure
|
||
*
|
||
* Programmer: Raymond Lu
|
||
* Friday, July 16, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_pop(H5E_t *estack, size_t count)
|
||
{
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT
|
||
|
||
/* Sanity check */
|
||
HDassert(estack);
|
||
HDassert(estack->nused >= count);
|
||
|
||
/* Remove the entries from the error stack */
|
||
if(H5E_clear_entries(estack, count) < 0)
|
||
HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "can't remove errors from stack")
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_pop() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5E_dump_api_stack
|
||
*
|
||
* Purpose: Private function to dump the error stack during an error in
|
||
* an API function if a callback function is defined for the
|
||
* current error stack.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Wednesday, August 6, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5E_dump_api_stack(hbool_t is_api)
|
||
{
|
||
herr_t ret_value = SUCCEED; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(FAIL)
|
||
|
||
/* Only dump the error stack during an API call */
|
||
if(is_api) {
|
||
H5E_t *estack = H5E_get_my_stack();
|
||
|
||
HDassert(estack);
|
||
|
||
#ifdef H5_NO_DEPRECATED_SYMBOLS
|
||
if(estack->auto_op.func2)
|
||
(void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
|
||
#else /* H5_NO_DEPRECATED_SYMBOLS */
|
||
if(estack->auto_op.vers == 1) {
|
||
if(estack->auto_op.func1)
|
||
(void)((estack->auto_op.func1)(estack->auto_data));
|
||
} /* end if */
|
||
else {
|
||
if(estack->auto_op.func2)
|
||
(void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
|
||
} /* end else */
|
||
#endif /* H5_NO_DEPRECATED_SYMBOLS */
|
||
} /* end if */
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5E_dump_api_stack() */
|
||
|