terom@3: #ifndef ERROR_H terom@3: #define ERROR_H terom@3: terom@3: /* terom@3: * Error-handling functions terom@3: */ terom@3: #include terom@3: terom@3: /* terom@3: * Type used for error codes is an explicitly *unsigned* int, meaning that error codes themselves are positive. terom@3: * Negative error codes also exist in some places, and they are just a negative err_t. terom@3: */ terom@3: typedef unsigned int err_t; terom@3: terom@3: /* terom@3: * List of defined error codes, organized mostly by function name terom@3: */ terom@3: enum error_code { terom@4: /* Core functions */ terom@3: ERR_CALLOC = 0x000100, terom@3: terom@4: /* Network resolver errors */ terom@3: ERR_GETADDRINFO = 0x000200, terom@3: ERR_GETADDRINFO_EMPTY = 0x000201, /* No valid results */ terom@3: terom@4: /* Low-level network errors */ terom@3: ERR_SOCKET = 0x000301, terom@3: ERR_CONNECT = 0x000302, terom@3: terom@4: /* Low-level IO errors */ terom@3: ERR_READ = 0x000401, terom@3: ERR_WRITE = 0x000402, terom@4: terom@4: /* GnuTLS errors */ terom@4: ERR_GNUTLS_CERT_ALLOC_CRED = 0x010101, terom@4: ERR_GNUTLS_GLOBAL_INIT = 0x010102, terom@3: }; terom@3: terom@3: /* terom@3: * An error code and associated extra infos terom@3: */ terom@3: struct error_info { terom@3: /* The base error code */ terom@3: err_t code; terom@3: terom@3: /* Additional detail info, usually some third-part error code */ terom@3: unsigned int extra; terom@3: }; terom@3: terom@3: /** No error, evaulates as logical false */ terom@3: #define SUCCESS (0) terom@3: terom@3: /* Evaulates to error_info.code as lvalue */ terom@4: #define ERROR_CODE(err_info_ptr) ((err_info_ptr)->code) terom@3: terom@3: /* Evaulates to error_info.extra as lvalue */ terom@4: #define ERROR_EXTRA(err_info_ptr) ((err_info_ptr)->extra) terom@3: terom@3: /* Set error_info.code to SUCCESS, evaulates as zero */ terom@4: #define RESET_ERROR(err_info_ptr) ((err_info_ptr)->code = SUCCESS) terom@3: terom@3: /* Compare error_info.code != 0 */ terom@4: #define IS_ERROR(err_info_ptr) (!!(err_info_ptr)->code) terom@3: terom@3: /* Set error_info.code, but leave err_extra as-is. Evaluates to err_code */ terom@4: #define SET_ERROR(err_info_ptr, err_code) ((err_info_ptr)->code = (err_code)) terom@3: terom@3: /* Set error_info.code/extra. XXX: should evaluate to err_code */ terom@4: #define _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra = (err_extra) terom@4: #define SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); } while (0) terom@3: terom@3: /* Set error.info.code to err_code, and .extra to errno. XXX: should evaulate to err_code */ terom@4: #define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno); terom@4: #define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno); terom@3: terom@3: /* Ss above, but also return err_code from func. XXX: use 'return SET_ERROR...' instead */ terom@4: #define RETURN_SET_ERROR(err_info_ptr, err_code) do { _SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0) terom@4: #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) terom@4: #define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0) terom@3: terom@3: #endif