Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright 2001-2004 Brandon Long
      3  * All Rights Reserved.
      4  *
      5  * ClearSilver Templating System
      6  *
      7  * This code is made available under the terms of the ClearSilver License.
      8  * http://www.clearsilver.net/license.hdf
      9  *
     10  */
     11 
     12 #ifndef __NEO_ERR_H_
     13 #define __NEO_ERR_H_ 1
     14 
     15 #include "util/neo_misc.h"
     16 
     17 /* For compilers (well, cpp actually) which don't define __PRETTY_FUNCTION__ */
     18 #ifndef __GNUC__
     19 #define __PRETTY_FUNCTION__ "unknown_function"
     20 #endif
     21 
     22 __BEGIN_DECLS
     23 
     24 /* For 64 bit systems which don't like mixing ints and pointers, we have the
     25  * _INT version for doing that comparison */
     26 #define STATUS_OK ((NEOERR *)0)
     27 #define STATUS_OK_INT 0
     28 #define INTERNAL_ERR ((NEOERR *)1)
     29 #define INTERNAL_ERR_INT 1
     30 
     31 /* NEOERR flags */
     32 #define NE_IN_USE (1<<0)
     33 
     34 typedef int NERR_TYPE;
     35 
     36 /* Predefined Error Types - These are all registered in nerr_init */
     37 extern NERR_TYPE NERR_PASS;
     38 extern NERR_TYPE NERR_ASSERT;
     39 extern NERR_TYPE NERR_NOT_FOUND;
     40 extern NERR_TYPE NERR_DUPLICATE;
     41 extern NERR_TYPE NERR_NOMEM;
     42 extern NERR_TYPE NERR_PARSE;
     43 extern NERR_TYPE NERR_OUTOFRANGE;
     44 extern NERR_TYPE NERR_SYSTEM;
     45 extern NERR_TYPE NERR_IO;
     46 extern NERR_TYPE NERR_LOCK;
     47 extern NERR_TYPE NERR_DB;
     48 extern NERR_TYPE NERR_EXISTS;
     49 
     50 typedef struct _neo_err
     51 {
     52   int error;
     53   int err_stack;
     54   int flags;
     55   char desc[256];
     56   const char *file;
     57   const char *func;
     58   int lineno;
     59   /* internal use only */
     60   struct _neo_err *next;
     61 } NEOERR;
     62 
     63 /* Technically, we could do this in configure and detect what their compiler
     64  * can handle, but for now... */
     65 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
     66 #define USE_C99_VARARG_MACROS 1
     67 #elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4) || defined (S_SPLINT_S)
     68 #define USE_GNUC_VARARG_MACROS 1
     69 #else
     70 #error The compiler is missing support for variable-argument macros.
     71 #endif
     72 
     73 
     74 /*
     75  * function: nerr_raise
     76  * description: Use this method to create an error "exception" for
     77  *              return up the call chain
     78  * arguments: using the macro, the function name, file, and lineno are
     79  *            automagically recorded for you.  You just provide the
     80  *            error (from those listed above) and the printf-style
     81  *            reason.  THIS IS A PRINTF STYLE FUNCTION, DO NOT PASS
     82  *            UNKNOWN STRING DATA AS THE FORMAT STRING.
     83  * returns: a pointer to a NEOERR, or INTERNAL_ERR if allocation of
     84  *          NEOERR fails
     85  */
     86 #if defined(USE_C99_VARARG_MACROS)
     87 #define nerr_raise(e,f,...) \
     88    nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
     89 #elif defined(USE_GNUC_VARARG_MACROS)
     90 #define nerr_raise(e,f,a...) \
     91    nerr_raisef(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
     92 #endif
     93 
     94 NEOERR *nerr_raisef (const char *func, const char *file, int lineno,
     95                      NERR_TYPE error, const char *fmt, ...)
     96                      ATTRIBUTE_PRINTF(5,6);
     97 
     98 
     99 
    100 #if defined(USE_C99_VARARG_MACROS)
    101 #define nerr_raise_errno(e,f,...) \
    102    nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
    103 #elif defined(USE_GNUC_VARARG_MACROS)
    104 #define nerr_raise_errno(e,f,a...) \
    105    nerr_raise_errnof(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
    106 #endif
    107 
    108 NEOERR *nerr_raise_errnof (const char *func, const char *file, int lineno,
    109                            int error, const char *fmt, ...)
    110                            ATTRIBUTE_PRINTF(5,6);
    111 
    112 /* function: nerr_pass
    113  * description: this function is used to pass an error up a level in the
    114  *              call chain (ie, if the error isn't handled at the
    115  *              current level).  This allows us to track the traceback
    116  *              of the error.
    117  * arguments: with the macro, the function name, file and lineno are
    118  *            automagically recorded.  Just pass the error.
    119  * returns: a pointer to an error
    120  */
    121 #define nerr_pass(e) \
    122    nerr_passf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e)
    123 
    124 NEOERR *nerr_passf (const char *func, const char *file, int lineno,
    125                     NEOERR *err);
    126 
    127 /* function: nerr_pass_ctx
    128  * description: this function is used to pass an error up a level in the
    129  *              call chain (ie, if the error isn't handled at the
    130  *              current level).  This allows us to track the traceback
    131  *              of the error.
    132  *              This version includes context information about lower
    133  *              errors
    134  * arguments: with the macro, the function name, file and lineno are
    135  *            automagically recorded.  Just pass the error and
    136  *            a printf format string giving more information about where
    137  *            the error is occuring.
    138  * returns: a pointer to an error
    139  */
    140 #if defined(USE_C99_VARARG_MACROS)
    141 #define nerr_pass_ctx(e,f,...) \
    142    nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,__VA_ARGS__)
    143 #elif defined(USE_GNUC_VARARG_MACROS)
    144 #define nerr_pass_ctx(e,f,a...) \
    145    nerr_pass_ctxf(__PRETTY_FUNCTION__,__FILE__,__LINE__,e,f,##a)
    146 #endif
    147 
    148 NEOERR *nerr_pass_ctxf (const char *func, const char *file, int lineno,
    149                         NEOERR *err, const char *fmt, ...)
    150                         ATTRIBUTE_PRINTF(5,6);
    151 
    152 /* function: nerr_log_error
    153  * description: currently, this prints out the error to stderr, and
    154  *             free's the error chain
    155  */
    156 void nerr_log_error (NEOERR *err);
    157 
    158 #include "util/neo_str.h"
    159 /* function: nerr_error_string
    160  * description: returns the string associated with an error (the bottom
    161  *              level of the error chain)
    162  * arguments: err - error
    163  *            str - string to which the data is appended
    164  * returns: None - errors appending to the string are ignored
    165  */
    166 void nerr_error_string (NEOERR *err, STRING *str);
    167 
    168 /* function: nerr_error_traceback
    169  * description: returns the full traceback of the error chain
    170  * arguments: err - error
    171  *            str - string to which the data is appended
    172  * returns: None - errors appending to the string are ignored
    173  */
    174 void nerr_error_traceback (NEOERR *err, STRING *str);
    175 
    176 /* function: nerr_ignore
    177  * description: you should only call this if you actually handle the
    178  *              error (should I rename it?).  Free's the error chain.
    179  */
    180 void nerr_ignore (NEOERR **err);
    181 
    182 /* function: nerr_register
    183  * description: register an error type.  This will assign a numeric value
    184  *              to the type, and keep track of the "pretty name" for it.
    185  * arguments: err - pointer to a NERR_TYPE
    186  *            name - pretty name for the error type
    187  * returns: NERR_NOMEM on no memory
    188  */
    189 NEOERR *nerr_register (NERR_TYPE *err, const char *name);
    190 
    191 /* function: nerr_init
    192  * description: initialize the NEOERR system.  Can be called more than once.
    193  *              Is not thread safe.  This registers all of the built in
    194  *              error types as defined at the top of this file.  If you don't
    195  *              call this, all exceptions will be returned as UnknownError.
    196  * arguments: None
    197  * returns: possibly NERR_NOMEM, but somewhat unlikely.  Possibly an
    198  *          UnknownError if NERR_NOMEM hasn't been registered yet.
    199  */
    200 NEOERR *nerr_init (void);
    201 
    202 /* function: nerr_match
    203  * description: nerr_match is used to walk the NEOERR chain and match
    204  *              the error against a specific error type.  In exception
    205  *              parlance, this would be the equivalent of "catch".
    206  *              Typically, you can just compare a NEOERR against STATUS_OK
    207  *              or just test for true if you are checking for any error.
    208  * arguments: err - the NEOERR that has an error.
    209  *            type - the NEOERR type, as registered with nerr_register
    210  * returns: true on match
    211  */
    212 int nerr_match (NEOERR *err, NERR_TYPE type);
    213 
    214 /* function: nerr_handle
    215  * description: nerr_handle is a convenience function.  It is the equivalent
    216  *              of nerr_match, but it will also deallocate the error chain
    217  *              on a match.
    218  * arguments: err - pointer to a pointer NEOERR
    219  *            type - the NEOERR type, as registered with nerr_register
    220  * returns: true on match
    221  */
    222 int nerr_handle (NEOERR **err, NERR_TYPE type);
    223 
    224 __END_DECLS
    225 
    226 #endif /* __NEO_ERR_H_ */
    227