/* -*- mode: C -*- */ /* IGraph library. Copyright (C) 2003, 2004, 2005 Gabor Csardi MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef IGRAPH_ERROR_H #define IGRAPH_ERROR_H #undef __BEGIN_DECLS #undef __END_DECLS #ifdef __cplusplus # define __BEGIN_DECLS extern "C" { # define __END_DECLS } #else # define __BEGIN_DECLS /* empty */ # define __END_DECLS /* empty */ #endif __BEGIN_DECLS /* This file contains the igraph error handling. * Most bits are taken literally from the GSL library (with the GSL_ * prefix renamed to IGRAPH_), as I couldn't find a better way to do * them. */ /** * \section errorhandlers Error handlers * * * If \a igraph runs into an error - an invalid argument was supplied * to a function, or we've ran out of memory - the control is * transferred to the \emb error handler \eme function. * * The default error handler is \ref igraph_error_handler_abort which * prints an error message and aborts the program. * * * The \ref igraph_set_error_handler() function can be used to set a new * error handler function of type \ref igraph_error_handler_t, see the * documentation of this type for details. * * * There are two other predefined error handler functions, * \ref igraph_error_handler_ignore and \ref igraph_error_handler_printignore, * these deallocate the temporarily allocated memory (more about this * later) and return with the error code. The latter also prints an * error message. If you use these error handlers you need to take * care about possible errors yourself by checking the return value of * every \a igraph function. * * Independently of the error handler installed, all functions in the * library do their best to leave their arguments * \em semantically unchanged if an error * happens. By semantically we mean that the implementation of an * object supplied as an argument might change, but its * \quote meaning \endquote in most cases does not. The rare occasions * when this rule is violated are documented in this manual. * */ /** * \section errorcodes Error codes * * Every \a igraph function which can fail return a * single integer error code. Some functions are very simple and * cannot run into any error, these may return other types, or * \type void as well. The error codes are defined by the * \ref igraph_i_error_type_t enumeration. * */ /** * \section writing_error_handlers Writing error handlers * * * You can write and install error handlers simply by defining a * function of type \ref igraph_error_handler_t and calling * \ref igraph_set_error_handler(). This feature is useful for interface * writers, as the \a igraph will have the chance to * signal errors the appropriate way, eg. the R interface defines an * error handler which calls the error() * function, as required by R, while the Python interface has an error * handler which raises an exception according to the Python way. * * * If you want to write an error handler, your error handler should * call \ref IGRAPH_FINALLY_FREE() to deallocate all temporary memory to * prevent memory leaks. * */ /** * \section error_handling_internals Error handling internals * * * If an error happens, the functions in the library call the * \ref IGRAPH_ERROR macro with a textual description of the error and an * \a igraph error code. This macro calls (through the \ref * igraph_error() function) the installed error handler. Another useful * macro is \ref IGRAPH_CHECK(), this checks the return value of its * argument which is normally a function call, and calls \ref * IGRAPH_ERROR if it is not \c IGRAPH_SUCCESS. * */ /** * \section deallocating_memory Deallocating memory * * * If a function runs into an error (and the program is not aborted) * the error handler should deallocate all temporary memory. This is * done by storing the address and the destroy function of all temporary * objects in a stack. The \ref IGRAPH_FINALLY function declares an object as * temporary by placing its address in the stack. If a function returns * with success it calls \ref IGRAPH_FINALLY_CLEAN() with the * number of objects to remove from the stack. If an error happens * however, the error handler should call \ref IGRAPH_FINALLY_FREE() to * deallocate each object added to the stack. This means that the * temporary objects allocated in the calling function (and etc.) will * be freed as well. * */ /** * \section writing_functions_error_handling Writing \a igraph functions with * proper error handling * * * There are some simple rules to keep in order to have functions * behaving well in erroneous situations. First, check the arguments * of the functions and call \ref IGRAPH_ERROR if they are invalid. Second, * call \ref IGRAPH_FINALLY on each dynamically allocated object and call * \ref IGRAPH_FINALLY_CLEAN() with the proper argument. Third, use * IGRAPH_CHECK on all function calls which can generate errors. * * * The size of the stack used for this bookkeeping is fixed, and * small. If you want to allocate several objects, write a destroy * function which can deallocate all of these. See the * adjlist.c file in the * \a igraph source for an example. * * * For some functions these mechanisms are simply not flexible * enough. These functions should define their own error handlers and * restore the error handler before they return. * */ /** * \section error_handling_threads Error handling and threads * * * It is likely that the \a igraph error handling * method is \em not thread-safe, mainly because of * the static global stack which is used to store the address of the * temporarily allocated objects. This issue might be addressed in a * later version of \a igraph. * */ /** * \typedef igraph_error_handler_t * * This is the type of the error handler functions. * \param reason Textual description of the error. * \param file The source file in which the error is noticed. * \param line The number of the line in the source file which triggered * the error * \param igraph_errno The \a igraph error code. */ typedef void igraph_error_handler_t (const char * reason, const char * file, int line, int igraph_errno); /** * \var igraph_error_handler_abort * * The default error handler, prints an error message and aborts the * program. */ extern igraph_error_handler_t igraph_error_handler_abort; /** * \var igraph_error_handler_ignore * * This error handler frees the temporarily allocated memory and returns * with the error code. */ extern igraph_error_handler_t igraph_error_handler_ignore; /** * \var igraph_error_handler_printignore * * Frees temporarily allocated memory, prints an error message to the * standard error and returns with the error code. */ extern igraph_error_handler_t igraph_error_handler_printignore; /** * \function igraph_set_error_handler * * Installs a new error handler. If called with 0, it installs the * default error handler (which is currently * \ref igraph_error_handler_abort). * \param new_handler The error handler function to install. * \return the old error handler function. This should be saved and * restored if \p new_handler is not needed any * more. */ igraph_error_handler_t* igraph_set_error_handler(igraph_error_handler_t new_handler); /** * \typedef igraph_i_error_type_t * \enumval IGRAPH_SUCCESS The function successfully completed its task. * \enumval IGRAPH_FAILURE Something went wrong. You'll almost never * meet this error as normally more specific error codes are used. * \enumval IGRAPH_ENOMEM There wasn't enough memory to allocate memory * on the heap. * \enumval IGRAPH_PARSEERROR A parse error was found in a file. * \enumval IGRAPH_EINVAL A parameter's value is invalid. Eg. negative * number was specified as the number of vertices. * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already * installed with the given name. * \enumval IGRAPH_EINVEVECTOR Invalid vector of vertex ids. A vertex id * is either negative or bigger than the number of vertices minus one. * \enumval IGRAPH_EINVVID Invalid vertex id, negative or too big. * \enumval IGRAPH_NONSQUARE A non-square matrix was received while a * square matrix was expected. * \enumval IGRAPH_EINVMODE Invalid mode parameter. * \enumval IGRAPH_EFILE A file operation failed. Eg. a file doesn't exist, * or the user ha no rights to open it. * \enumval IGRAPH_EUNFOLDINF Attempted to unfold an infinite iterator. * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or * disabled (at compile-time) function. * \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge. */ typedef enum { IGRAPH_SUCCESS = 0, IGRAPH_FAILURE = 1, IGRAPH_ENOMEM = 2, IGRAPH_PARSEERROR = 3, IGRAPH_EINVAL = 4, IGRAPH_EXISTS = 5, IGRAPH_EINVEVECTOR = 6, IGRAPH_EINVVID = 7, IGRAPH_NONSQUARE = 8, IGRAPH_EINVMODE = 9, IGRAPH_EFILE = 10, IGRAPH_EUNFOLDINF = 11, IGRAPH_UNIMPLEMENTED = 12, IGRAPH_INTERRUPTED = 13, IGRAPH_DIVERGED = 14, } igraph_i_error_type_t; /** * \define IGRAPH_ERROR * * This macro is called if an error is noticed. It calls * \ref igraph_error() with the proper parameters and if that returns * the macro returns the "calling" function as well, with the error * code. If for some (suspicious) reason you want to call the error * handler without returning from the current function, call * \ref igraph_error() directly. * \param reason Textual description of the error. This should be * something more explaning than the text associated with the error * code. Eg. if the error code is \c IGRAPH_EINVAL, * its asssociated text (see \ref igraph_strerror()) is "Invalid * value" and this string should explain which parameter was invalid * and maybe why. * \param igraph_errno The \a igraph error code. */ #define IGRAPH_ERROR(reason, igraph_errno) \ do { \ igraph_error (reason, __FILE__, __LINE__, igraph_errno) ; \ return igraph_errno ; \ } while (0) /** * \function igraph_error * * This is the function which is called (usually via the * \ref IGRAPH_ERROR macro) if an error is noticed. See the discussion of * this macro as well. * * \param reason Textual description of the error. * \param file The source file in which the error was noticed. * \param line The number of line in the source file which triggered the * error. * \param igraph_errno The \a igraph error code. * \return the error code (if it returns) */ int igraph_error(const char *reason, const char *file, int line, int igraph_errno); /** * \function igraph_strerror * * This is a simple utility function, it gives a short general textual * description for an \a igraph error code. * * \param igraph_errno The \a igraph error code. * \return pointer to the textual description of the error code. */ const char* igraph_strerror(const int igraph_errno); #define IGRAPH_ERROR_SELECT_2(a,b) ((a) != IGRAPH_SUCCESS ? (a) : ((b) != IGRAPH_SUCCESS ? (b) : IGRAPH_SUCCESS)) #define IGRAPH_ERROR_SELECT_3(a,b,c) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_2(b,c)) #define IGRAPH_ERROR_SELECT_4(a,b,c,d) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_3(b,c,d)) #define IGRAPH_ERROR_SELECT_5(a,b,c,d,e) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_4(b,c,d,e)) /* Now comes the more conveninent error handling macro arsenal. * Ideas taken from exception.{h,c} by Laurent Deniau see * http://cern.ch/Laurent.Deniau/html/oopc/oopc.html#Exceptions for more * information. We don't use the exception handling code though. */ struct igraph_i_protectedPtr { int all; void *ptr; void (*func)(void*); }; typedef void igraph_finally_func_t (void*); void IGRAPH_FINALLY_REAL(void (*func)(void*), void* ptr); /** * \function IGRAPH_FINALLY_CLEAN * * Removes the specified number of objects from the stack of * temporarily allocated objects. Most often this is called just * before returning from a function. * \param num The number of objects to remove from the bookkeeping * stack. */ void IGRAPH_FINALLY_CLEAN(int num); /** * \function IGRAPH_FINALLY_FREE * * Calls the destroy function for all objects in the stack of * temporarily allocated objects. This is usually called only from an * error handler. It is \em not appropriate to use it * instead of destroying each unneeded object of a function, as it * destroys the temporary objects of the caller function (and so on) * as well. */ void IGRAPH_FINALLY_FREE(void); /** * \define IGRAPH_FINALLY * \param func The address of the function which is normally called to * destroy the object. * \param ptr Pointer to the object itself. * * This macro places the address of an object, together with the * address of its destructor in a stack. This stack is used if an * error happens to deallocate temporarily allocated objects to * prevent memory leaks. */ #define IGRAPH_FINALLY(func, ptr) \ IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr)) /** * \define IGRAPH_CHECK * * \param a An expression, usually a function call. * * Executes the expression and checks its value. If this is not * \c IGRAPH_SUCCESS, it calls \ref IGRAPH_ERROR with * the value as the error code. Here is an example usage: * \verbatim IGRAPH_CHECK(vector_push_back(&v, 100)); \endverbatim */ #define IGRAPH_CHECK(a) do { \ int igraph_i_ret=(a); \ if (igraph_i_ret != 0) { \ IGRAPH_ERROR("", igraph_i_ret); \ } } while(0) typedef igraph_error_handler_t igraph_warning_handler_t; igraph_warning_handler_t* igraph_set_warning_handler(igraph_warning_handler_t new_handler); extern igraph_warning_handler_t igraph_warning_handler_print; int igraph_warning(const char *reason, const char *file, int line, int igraph_errno); #define IGRAPH_WARNING(reason) \ do { \ igraph_warning(reason, __FILE__, __LINE__, -1); \ } while (0) __END_DECLS #endif