src/error.h
author Tero Marttila <terom@fixme.fi>
Sun, 15 Mar 2009 23:22:57 +0200
branchmodules
changeset 57 ce1accba5fc7
parent 56 942370000450
child 63 d399a1d915a3
permissions -rw-r--r--
slight cleanup to move module funcs to a 'struct module_funcs'
#ifndef ERROR_H
#define ERROR_H

/**
 * @file
 *
 * Error-handling functions
 */
#include <errno.h>

/**
 * The type used for error codes is an explicitly *unsigned* int, meaning that error codes themselves are positive.
 * Negative error codes (as signed ints) also exist in some places, and they are just a negative err_t.
 */
typedef unsigned int err_t;

/**
 * Ways to interpret error_info.extra
 */
enum error_extra_types {
    /** No extra info */
    ERR_EXTRA_NONE      = 0,

    /** libc errno, using strerror() */
    ERR_EXTRA_ERRNO,

    /** libc resolver, using gai_strerror() */
    ERR_EXTRA_GAI,

    /** GnuTLS, using gnutls_strerror() */
    ERR_EXTRA_GNUTLS,

    /** Static error message string */
    ERR_EXTRA_STR,
};

/**
 * List of defined error codes, organized mostly by function name
 */
enum error_code {
    _ERR_INVALID    = 0x000000,
    
    /** stdlib.h functions */
    _ERR_STDLIB     = 0x000100,
    ERR_CALLOC,
    ERR_STRDUP,
    
    /** DNS resolver */
    _ERR_RESOLVER   = 0x000200,
    ERR_GETADDRINFO,
    ERR_GETADDRINFO_EMPTY, 
    
    /** @see sock_error_code*/
    _ERR_SOCK       = 0x000300,

    /** @see sock_gnutls_error_code */
    _ERR_GNUTLS     = 0x000400,

    /** Libevent errors */
    _ERR_LIBEVENT   = 0x000500,
    ERR_EVENT_NEW,
    ERR_EVENT_ADD,

    /** Evsql errors */
    _ERR_EVSQL      = 0x000600,
    ERR_EVSQL_NEW_PQ,

    /** irc_proto errors */
    _ERR_IRC_LINE   = 0x000700,
    ERR_LINE_TOO_LONG,
    ERR_LINE_INVALID_TOKEN,
    ERR_INVALID_NM,
    ERR_INVALID_NICK_LENGTH,

    /** irc_conn errors */
    _ERR_IRC_CONN   = 0x000800,
    ERR_IRC_CONN_REGISTER_STATE,
    ERR_IRC_CONN_QUIT_STATE,

    /** irc_net errors */
    _ERR_IRC_NET    = 0x000900,
    ERR_IRC_NET_QUIT_STATE,

    /** @see module_error_code */
    _ERR_MODULE     = 0x000a00,
};

/**
 * Table of error descriptions
 */
struct error_desc {
    /** The flat error code */
    err_t code;

    /** The short name */
    const char *name;

    /** How to interpret .extra */
    enum error_extra_types extra_type;
};

/**
 * An error code and associated extra infos
 */
struct error_info {
    /** The base error code */
    err_t code;
    
    union {
        /** Additional detail info, usually some third-party error code, as defined by the code's ERR_EXTRA_* */
        int extra;

        /** Additional info, stored as a pointer to a static string (note how dangerous this is) */
        const char *extra_str;
    };
};

/**
 * Translate an err_t into a function name.
 */
const char *error_name (err_t code);

/**
 * Maximum length of error messages returned by error_msg (including NUL byte)
 */
#define ERROR_MSG_MAXLEN 1024

/**
 * Translate an error_info into a message.
 *
 * This is returned as a pointer into a statically allocated buffer. It is not re-entrant.
 */
const char *error_msg (const struct error_info *err);

/** No error, evaulates as logical false */
#define SUCCESS (0)

/** Evaulates to error_info.code as lvalue */
#define ERROR_CODE(err_info_ptr) ((err_info_ptr)->code)

/** Evaulates to error_info.extra as lvalue */
#define ERROR_EXTRA(err_info_ptr) ((err_info_ptr)->extra)

/** Set error_info.code to SUCCESS, evaulates as zero */
#define RESET_ERROR(err_info_ptr) ((err_info_ptr)->code = SUCCESS)

/** Compare error_info.code != 0 */
#define IS_ERROR(err_info_ptr) (!!(err_info_ptr)->code)

/** Compare the err_code/err_extra for an err_info */
#define MATCH_ERROR(err_info_ptr, err_code, err_extra) ((err_info_ptr)->code == (err_code) && (err_info_ptr)->extra == (err_extra))

/** Set error_info.code, but leave err_extra as-is. Evaluates to err_code */
#define SET_ERROR(err_info_ptr, err_code) ((err_info_ptr)->code = (err_code))

/** Set error_info.code/extra. XXX: should evaluate to err_code */
#define _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra = (err_extra)
#define SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); } while (0)

/** Set error_info.code to err_code, and .extra to errno. XXX: should evaulate to err_code */
#define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
#define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno);

/** 
 * Set error_info.code to err_code, and .extra_str to str. The given string pointer should remain valid while the error
 * is being handled down-stack.
 */
#define _SET_ERROR_STR(err_info_ptr, err_code, err_str) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra_str = (err_str)
#define SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); } while(0)

/** Set error_info from another error_info. Evaluates to the new error_info */
#define SET_ERROR_INFO(err_info_ptr, from_ptr) (*err_info_ptr = *from_ptr)

/** Same as above, but also return err_code from func. XXX: use 'return SET_ERROR...' instead */
#define RETURN_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0)
#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)
#define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0)
#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)
#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)

/** Same as above, but also do a 'goto error' */
#define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
#define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
#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)

#endif