src/error.h
branchnew-lib-errors
changeset 216 a10ba529ae39
parent 215 85863b89e38b
child 217 7728d6ec3abf
equal deleted inserted replaced
215:85863b89e38b 216:a10ba529ae39
     1 #ifndef ERROR_H
       
     2 #define ERROR_H
       
     3 
       
     4 /**
       
     5  * @file
       
     6  *
       
     7  * Error-handling functions
       
     8  */
       
     9 #include <errno.h>
       
    10 #include <stdbool.h>
       
    11 
       
    12 /**
       
    13  * The type used for error codes is an explicitly *unsigned* int, meaning that error codes themselves are positive.
       
    14  * Negative error codes (as signed ints) also exist in some places, and they are just a negative err_t.
       
    15  */
       
    16 typedef unsigned int err_t;
       
    17 
       
    18 /**
       
    19  * Ways to interpret error_info.extra
       
    20  */
       
    21 enum error_extra_types {
       
    22     /** No extra info */
       
    23     ERR_EXTRA_NONE      = 0,
       
    24 
       
    25     /** libc errno, using strerror() */
       
    26     ERR_EXTRA_ERRNO,
       
    27 
       
    28     /** libc resolver, using gai_strerror() */
       
    29     ERR_EXTRA_GAI,
       
    30 
       
    31     /** GnuTLS, using gnutls_strerror() */
       
    32     ERR_EXTRA_GNUTLS,
       
    33 
       
    34     /** Static error message string */
       
    35     ERR_EXTRA_STR,
       
    36 };
       
    37 
       
    38 /**
       
    39  * List of defined error codes, organized mostly by function name
       
    40  */
       
    41 enum error_code {
       
    42     _ERR_INVALID    = 0x000000,
       
    43     
       
    44     /** stdlib.h functions */
       
    45     _ERR_STDLIB     = 0x000100,
       
    46     ERR_CALLOC,
       
    47     ERR_STRDUP,
       
    48     ERR_SIGACTION,
       
    49     ERR_ACCESS_READ,
       
    50     
       
    51     /** DNS resolver */
       
    52     _ERR_RESOLVER   = 0x000200,
       
    53     ERR_GETADDRINFO,
       
    54     ERR_GETADDRINFO_EMPTY, 
       
    55     
       
    56     /** socket/IO errors */
       
    57     _ERR_SOCK       = 0x000300,
       
    58     ERR_SOCKET,         ///< socket(2) failed
       
    59     ERR_CONNECT,        ///< connect(2) error - either direct or async
       
    60     ERR_READ,           ///< read(2) error - will probably show up as an ERR_WRITE as well
       
    61     ERR_WRITE,          ///< write(2) error - data was unsent, will probably show up as an ERR_READ as well
       
    62     ERR_WRITE_EOF,      ///< write(2) gave EOF - zero bytes written
       
    63     ERR_FCNTL,          ///< fcntl(2) failed
       
    64     ERR_CLOSE,          ///< close(2) failed, some written data was probably not sent
       
    65     ERR_GETSOCKOPT,     ///< getsockopt(2) failed
       
    66     ERR_OPEN,           ///< open(2) failed
       
    67     ERR_ACCEPT,         ///< accept(2) failed
       
    68     ERR_BIND,           ///< bind(2) failed
       
    69     ERR_LISTEN,         ///< listen(2) failed
       
    70 
       
    71     /** @see sock_gnutls_error_code */
       
    72     _ERR_GNUTLS     = 0x000400,
       
    73 
       
    74     /** Libevent errors */
       
    75     _ERR_LIBEVENT   = 0x000500,
       
    76     ERR_EVENT_NEW,
       
    77     ERR_EVENT_ADD,
       
    78     ERR_EVENT_DEL,
       
    79 
       
    80     /** Evsql errors */
       
    81     _ERR_EVSQL      = 0x000600,
       
    82     ERR_EVSQL_NEW_PQ,
       
    83     ERR_EVSQL_QUERY_EXEC,
       
    84 
       
    85     /** irc_proto errors */
       
    86     _ERR_IRC_LINE   = 0x000700,
       
    87     ERR_LINE_TOO_LONG,
       
    88     ERR_LINE_INVALID_TOKEN,
       
    89     ERR_INVALID_NM,
       
    90     ERR_INVALID_NICK_LENGTH,
       
    91 
       
    92     /** irc_conn errors */
       
    93     _ERR_IRC_CONN   = 0x000800,
       
    94     ERR_IRC_CONN_REGISTER_STATE,
       
    95     ERR_IRC_CONN_QUIT_STATE,
       
    96 
       
    97     /** irc_net errors */
       
    98     _ERR_IRC_NET    = 0x000900,
       
    99     ERR_IRC_NET_INFO,
       
   100     ERR_IRC_NET_STATE,
       
   101 
       
   102     /** @see module_error_code */
       
   103     _ERR_MODULE     = 0x000a00,
       
   104 
       
   105     /** config errors */
       
   106     _ERR_CONFIG     = 0x000b00,
       
   107     ERR_CONFIG_NAME,        ///< unknown option name
       
   108     ERR_CONFIG_TYPE,        ///< invalid value type for parameter
       
   109     ERR_CONFIG_REQUIRED,    ///< missing value for required parameter
       
   110     ERR_CONFIG_VALUE,       ///< invalid value
       
   111     ERR_CONFIG_PARAMS,      ///< invalid number of parameters
       
   112     
       
   113     /** lua errors */
       
   114     _ERR_LUA        = 0x000c00,
       
   115     ERR_LUA_MEM,
       
   116     ERR_LUA_SYNTAX,
       
   117     ERR_LUA_RUN,
       
   118     ERR_LUA_ERR,
       
   119     ERR_LUA_FILE,
       
   120 
       
   121     /** irc_chan errors */
       
   122     _ERR_IRC_CHAN   = 0x000d00,
       
   123     ERR_IRC_CHAN_STATE,
       
   124 
       
   125     /** pcre errors */
       
   126     _ERR_PCRE       = 0x000e00,
       
   127     ERR_PCRE_COMPILE,       ///< pcre_compile: <error_msg>
       
   128     ERR_PCRE_EXEC,          ///< pcre_exec: <error code>
       
   129 
       
   130     /** str errors */
       
   131     _ERR_STR        = 0x000f00,
       
   132 
       
   133     /** Transport errors */
       
   134     _ERR_TRANSPORT  = 0x001000,
       
   135 
       
   136     /** General errors */
       
   137     _ERR_GENERAL    = 0xffff00,
       
   138     ERR_MISC,               ///< general error
       
   139     ERR_CMD_OPT,            ///< invalid commandline option
       
   140     ERR_UNKNOWN,
       
   141     ERR_DUP_NAME,           ///< duplicate name
       
   142     ERR_EOF,                ///< end of file
       
   143     ERR_MEM,                ///< memory allocation error
       
   144     ERR_NOT_IMPLEMENTED,    ///< function not implemented
       
   145 };
       
   146 
       
   147 /**
       
   148  * Table of error descriptions
       
   149  */
       
   150 struct error_desc {
       
   151     /** The flat error code */
       
   152     err_t code;
       
   153 
       
   154     /** The short name */
       
   155     const char *name;
       
   156 
       
   157     /** How to interpret .extra */
       
   158     enum error_extra_types extra_type;
       
   159 };
       
   160 
       
   161 /**
       
   162  * An error code and associated extra infos
       
   163  */
       
   164 struct error_info {
       
   165     /** 
       
   166      * The base error code.
       
   167      *
       
   168      * This is a signed int because we need to be able to manipulate negative errors codes as well.
       
   169      */
       
   170     signed int code;
       
   171     
       
   172     union {
       
   173         /** Additional detail info, usually some third-party error code, as defined by the code's ERR_EXTRA_* */
       
   174         int extra;
       
   175 
       
   176         /** Additional info, stored as a pointer to a static string (note how dangerous this is) */
       
   177         const char *extra_str;
       
   178     };
       
   179 };
       
   180 
       
   181 /**
       
   182  * The public names
       
   183  */
       
   184 typedef struct error_info error_t;
       
   185 
       
   186 /**
       
   187  * Translate an err_t into a function name.
       
   188  */
       
   189 const char *error_name (err_t code);
       
   190 
       
   191 /**
       
   192  * Look up the error_desc for the given error code
       
   193  */
       
   194 const struct error_desc* error_lookup (err_t code);
       
   195 
       
   196 /**
       
   197  * Maximum length of error messages returned by error_msg (including NUL byte)
       
   198  */
       
   199 #define ERROR_MSG_MAXLEN 1024
       
   200 
       
   201 /**
       
   202  * Translate an error_info into a message.
       
   203  *
       
   204  * This is returned as a pointer into a statically allocated buffer. It is not re-entrant.
       
   205  */
       
   206 const char *error_msg (const error_t *err);
       
   207 
       
   208 /**
       
   209  * Compare the given errors for equivalency
       
   210  */
       
   211 bool error_cmp_eq (const error_t *a, const error_t *b);
       
   212 
       
   213 /** No error, evaulates as logical false */
       
   214 #define SUCCESS (0)
       
   215 
       
   216 /** Evaulates to error_info.code as lvalue */
       
   217 #define ERROR_CODE(err_info_ptr) ((err_info_ptr)->code)
       
   218 
       
   219 /** Evaulates to error_info.extra as lvalue */
       
   220 #define ERROR_EXTRA(err_info_ptr) ((err_info_ptr)->extra)
       
   221 
       
   222 /** Set error_info.code to SUCCESS, evaulates as zero */
       
   223 #define RESET_ERROR(err_info_ptr) ((err_info_ptr)->code = SUCCESS)
       
   224 
       
   225 /** Compare error_info.code != 0 */
       
   226 #define IS_ERROR(err_info_ptr) (!!(err_info_ptr)->code)
       
   227 
       
   228 /** Compare the err_code/err_extra for an err_info */
       
   229 #define MATCH_ERROR(err_info_ptr, err_code, err_extra) ((err_info_ptr)->code == (err_code) && (err_info_ptr)->extra == (err_extra))
       
   230 
       
   231 /** Set error_info.code, but leave err_extra as-is. Evaluates to err_code */
       
   232 #define SET_ERROR(err_info_ptr, err_code) ((err_info_ptr)->code = (err_code))
       
   233 
       
   234 /** Set error_info.code/extra. XXX: should evaluate to err_code */
       
   235 #define _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra = (err_extra)
       
   236 #define SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); } while (0)
       
   237 
       
   238 /** Set error_info.code to err_code, and .extra to errno. XXX: should evaulate to err_code */
       
   239 #define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
       
   240 #define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
       
   241 
       
   242 /** 
       
   243  * Set error_info.code to err_code, and .extra_str to str. The given string pointer should remain valid while the error
       
   244  * is being handled down-stack.
       
   245  */
       
   246 #define _SET_ERROR_STR(err_info_ptr, err_code, err_str) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra_str = (err_str)
       
   247 #define SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); } while(0)
       
   248 
       
   249 /** Set error_info from another error_info. Evaluates to the new error_info */
       
   250 #define SET_ERROR_INFO(err_info_ptr, from_ptr) (*err_info_ptr = *from_ptr)
       
   251 
       
   252 /** Same as above, but also return err_code from func. XXX: use 'return SET_ERROR...' instead */
       
   253 #define RETURN_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0)
       
   254 #define RETURN_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); return (err_code); } while (0)
       
   255 #define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0)
       
   256 #define RETURN_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); return (from_ptr->code); } while (0)
       
   257 #define RETURN_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); return (err_code); } while (0)
       
   258 
       
   259 /** Same as above, but also do a 'goto error' */
       
   260 #define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
       
   261 #define JUMP_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); goto error; } while (0)
       
   262 #define JUMP_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); goto error; } while (0)
       
   263 #define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
       
   264 #define JUMP_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); goto error; } while (0)
       
   265 
       
   266 /**
       
   267  * Macro used to mark code segments that should never be executed (e.g. switch-default), kind of like assert
       
   268  */
       
   269 #include <stdlib.h>
       
   270 #define NOT_REACHED(val) abort()
       
   271 
       
   272 #endif