/* * 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_ */