/*
* Copyright 2001-2004 Brandon Long
* All Rights Reserved.
*
* ClearSilver Templating System
*
* This code is made available under the terms of the ClearSilver License.
* http://www.clearsilver.net/license.hdf
*
*/
#ifndef __NEO_ERR_H_
#define __NEO_ERR_H_ 1
#include "util/neo_misc.h"
/* For compilers (well, cpp actually) which don't define __PRETTY_FUNCTION__ */
#ifndef __GNUC__
#define __PRETTY_FUNCTION__ "unknown_function"
#endif
__BEGIN_DECLS
/* For 64 bit systems which don't like mixing ints and pointers, we have the
* _INT version for doing that comparison */
#define STATUS_OK ((NEOERR *)0)
#define STATUS_OK_INT 0
#define INTERNAL_ERR ((NEOERR *)1)
#define INTERNAL_ERR_INT 1
/* NEOERR flags */
#define NE_IN_USE (1<<0)
typedef int NERR_TYPE;
/* Predefined Error Types - These are all registered in nerr_init */
extern NERR_TYPE NERR_PASS;
extern NERR_TYPE NERR_ASSERT;
extern NERR_TYPE NERR_NOT_FOUND;
extern NERR_TYPE NERR_DUPLICATE;
extern NERR_TYPE NERR_NOMEM;
extern NERR_TYPE NERR_PARSE;
extern NERR_TYPE NERR_OUTOFRANGE;
extern NERR_TYPE NERR_SYSTEM;
extern NERR_TYPE NERR_IO;
extern NERR_TYPE NERR_LOCK;
extern NERR_TYPE NERR_DB;
extern NERR_TYPE NERR_EXISTS;
typedef struct _neo_err
{
int error;
int err_stack;
int flags;
char desc[256];
const char *file;
const char *func;
int lineno;
/* internal use only */
struct _neo_err *next;
} NEOERR;
/* Technically, we could do this in configure and detect what their compiler
* can handle, but for now... */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define USE_C99_VARARG_MACROS 1
#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4) || defined (S_SPLINT_S)
#define USE_GNUC_VARARG_MACROS 1
#else
#error The compiler is missing support for variable-argument macros.
#endif
/*
* function: nerr_raise
* description: Use this method to create an error "exception" for
* return up the call chain
* arguments: using the macro, the function name, file, and lineno are
* automagically recorded for you. You just provide the
* error (from those listed above) and the printf-style
* reason. THIS IS A PRINTF STYLE FUNCTION, DO NOT PASS
* UNKNOWN STRING DATA AS THE FORMAT STRING.
* returns: a pointer to a NEOERR, or INTERNAL_ERR if allocation of
* NEOERR fails
*/
#if defined(USE_C99_VARARG_MACROS)
#define nerr_raise(e,f,...) \
nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
#elif defined(USE_GNUC_VARARG_MACROS)
#define nerr_raise(e,f,a...) \
nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
#endif
NEOERR *nerr_raisef (const char *func, const char *file, int lineno,
NERR_TYPE error, const char *fmt, ...)
ATTRIBUTE_PRINTF(5,6);
#if defined(USE_C99_VARARG_MACROS)
#define nerr_raise_errno(e,f,...) \
nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
#elif defined(USE_GNUC_VARARG_MACROS)
#define nerr_raise_errno(e,f,a...) \
nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
#endif
NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno,
int error, const char *fmt, ...)
ATTRIBUTE_PRINTF(5,6);
/* function: nerr_pass
* description: this function is used to pass an error up a level in the
* call chain (ie, if the error isn't handled at the
* current level). This allows us to track the traceback
* of the error.
* arguments: with the macro, the function name, file and lineno are
* automagically recorded. Just pass the error.
* returns: a pointer to an error
*/
#define nerr_pass(e) \
nerr_passf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e)
NEOERR *nerr_passf (const char *func, const char *file, int lineno,
NEOERR *err);
/* function: nerr_pass_ctx
* description: this function is used to pass an error up a level in the
* call chain (ie, if the error isn't handled at the
* current level). This allows us to track the traceback
* of the error.
* This version includes context information about lower
* errors
* arguments: with the macro, the function name, file and lineno are
* automagically recorded. Just pass the error and
* a printf format string giving more information about where
* the error is occuring.
* returns: a pointer to an error
*/
#if defined(USE_C99_VARARG_MACROS)
#define nerr_pass_ctx(e,f,...) \
nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
#elif defined(USE_GNUC_VARARG_MACROS)
#define nerr_pass_ctx(e,f,a...) \
nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
#endif
NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno,
NEOERR *err, const char *fmt, ...)
ATTRIBUTE_PRINTF(5,6);
/* function: nerr_log_error
* description: currently, this prints out the error to stderr, and
* free's the error chain
*/
void nerr_log_error (NEOERR *err);
#include "util/neo_str.h"
/* function: nerr_error_string
* description: returns the string associated with an error (the bottom
* level of the error chain)
* arguments: err - error
* str - string to which the data is appended
* returns: None - errors appending to the string are ignored
*/
void nerr_error_string (NEOERR *err, STRING *str);
/* function: nerr_error_traceback
* description: returns the full traceback of the error chain
* arguments: err - error
* str - string to which the data is appended
* returns: None - errors appending to the string are ignored
*/
void nerr_error_traceback (NEOERR *err, STRING *str);
/* function: nerr_ignore
* description: you should only call this if you actually handle the
* error (should I rename it?). Free's the error chain.
*/
void nerr_ignore (NEOERR **err);
/* function: nerr_register
* description: register an error type. This will assign a numeric value
* to the type, and keep track of the "pretty name" for it.
* arguments: err - pointer to a NERR_TYPE
* name - pretty name for the error type
* returns: NERR_NOMEM on no memory
*/
NEOERR *nerr_register (NERR_TYPE *err, const char *name);
/* function: nerr_init
* description: initialize the NEOERR system. Can be called more than once.
* Is not thread safe. This registers all of the built in
* error types as defined at the top of this file. If you don't
* call this, all exceptions will be returned as UnknownError.
* arguments: None
* returns: possibly NERR_NOMEM, but somewhat unlikely. Possibly an
* UnknownError if NERR_NOMEM hasn't been registered yet.
*/
NEOERR *nerr_init (void);
/* function: nerr_match
* description: nerr_match is used to walk the NEOERR chain and match
* the error against a specific error type. In exception
* parlance, this would be the equivalent of "catch".
* Typically, you can just compare a NEOERR against STATUS_OK
* or just test for true if you are checking for any error.
* arguments: err - the NEOERR that has an error.
* type - the NEOERR type, as registered with nerr_register
* returns: true on match
*/
int nerr_match (NEOERR *err, NERR_TYPE type);
/* function: nerr_handle
* description: nerr_handle is a convenience function. It is the equivalent
* of nerr_match, but it will also deallocate the error chain
* on a match.
* arguments: err - pointer to a pointer NEOERR
* type - the NEOERR type, as registered with nerr_register
* returns: true on match
*/
int nerr_handle (NEOERR **err, NERR_TYPE type);
__END_DECLS
#endif /* __NEO_ERR_H_ */