diff options
Diffstat (limited to 'libmisc/include')
-rw-r--r-- | libmisc/include/libmisc/error.h | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/libmisc/include/libmisc/error.h b/libmisc/include/libmisc/error.h new file mode 100644 index 0000000..4110626 --- /dev/null +++ b/libmisc/include/libmisc/error.h @@ -0,0 +1,167 @@ +/* libmisc/error.h - Go-esque errors + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_ERROR_H_ +#define _LIBMISC_ERROR_H_ + +#include <stddef.h> /* for size_t */ +#include <stdint.h> /* for uint{n}_t */ + +#include <libmisc/assert.h> +#include <libmisc/fmt.h> + +/* _errnum ********************************************************************/ + +typedef enum { + /* Original to libmisc */ + E_NOERROR = 0, /* no error */ + E_EOF, /* EOF */ + E_NET_EARP_TIMEOUT, /* ARP timeout */ + E_NET_EACK_TIMEOUT, /* TCP ACK timeout */ + E_NET_ERECV_TIMEOUT, /* receive timeout */ + E_NET_ECLOSED, /* already closed */ + /* At least C99 through C23 */ + E_STDC_EDOM, + E_STDC_EILSEQ, + E_STDC_ERANGE, + /* POSIX-2024 */ + E_POSIX_E2BIG, /* Argument list too long */ + E_POSIX_EACCES, /* Permission denied */ + E_POSIX_EADDRINUSE, /* Address in use */ + E_POSIX_EADDRNOTAVAIL, /* Address not available */ + E_POSIX_EAFNOSUPPORT, /* Address family not supported */ + E_POSIX_EAGAIN, /* Resource unavailable, try again (may be the same value as [EWOULDBLOCK]) */ + E_POSIX_EALREADY, /* Connection already in progress */ + E_POSIX_EBADF, /* Bad file descriptor */ + E_POSIX_EBADMSG, /* Bad message */ + E_POSIX_EBUSY, /* Device or resource busy */ + E_POSIX_ECANCELED, /* Operation canceled */ + E_POSIX_ECHILD, /* No child processes */ + E_POSIX_ECONNABORTED, /* Connection aborted */ + E_POSIX_ECONNREFUSED, /* Connection refused */ + E_POSIX_ECONNRESET, /* Connection reset */ + E_POSIX_EDEADLK, /* Resource deadlock would occur */ + E_POSIX_EDESTADDRREQ, /* Destination address required */ +#define E_POSIX_EDOM E_STDC_EDOM /* Mathematics argument out of domain of function */ + E_POSIX_EDQUOT, /* Reserved */ + E_POSIX_EEXIST, /* File exists */ + E_POSIX_EFAULT, /* Bad address */ + E_POSIX_EFBIG, /* File too large */ + E_POSIX_EHOSTUNREACH, /* Host is unreachable */ + E_POSIX_EIDRM, /* Identifier removed */ +#define E_POSIX_EILSEQ E_STDC_EILSEQ /* Illegal byte sequence */ /* (in the context of text encoding) */ + E_POSIX_EINPROGRESS, /* Operation in progress */ + E_POSIX_EINTR, /* Interrupted function */ + E_POSIX_EINVAL, /* Invalid argument */ + E_POSIX_EIO, /* I/O error */ + E_POSIX_EISCONN, /* Socket is connected */ + E_POSIX_EISDIR, /* Is a directory */ + E_POSIX_ELOOP, /* Too many levels of symbolic links */ + E_POSIX_EMFILE, /* File descriptor value too large */ + E_POSIX_EMLINK, /* Too many hard links */ + E_POSIX_EMSGSIZE, /* Message too large */ + E_POSIX_EMULTIHOP, /* Reserved */ + E_POSIX_ENAMETOOLONG, /* Filename too long */ + E_POSIX_ENETDOWN, /* Network is down */ + E_POSIX_ENETRESET, /* Connection aborted by network */ + E_POSIX_ENETUNREACH, /* Network unreachable */ + E_POSIX_ENFILE, /* Too many files open in system */ + E_POSIX_ENOBUFS, /* No buffer space available */ + E_POSIX_ENODEV, /* No such device */ + E_POSIX_ENOENT, /* No such file or directory */ + E_POSIX_ENOEXEC, /* Executable file format error */ + E_POSIX_ENOLCK, /* No locks available */ + E_POSIX_ENOLINK, /* Reserved */ + E_POSIX_ENOMEM, /* Not enough space */ + E_POSIX_ENOMSG, /* No message of the desired type */ + E_POSIX_ENOPROTOOPT, /* Protocol not available */ + E_POSIX_ENOSPC, /* No space left on device */ + E_POSIX_ENOSYS, /* Functionality not supported */ + E_POSIX_ENOTCONN, /* The socket is not connected */ + E_POSIX_ENOTDIR, /* Not a directory or a symbolic link to a directory */ + E_POSIX_ENOTEMPTY, /* Directory not empty */ + E_POSIX_ENOTRECOVERABLE, /* State not recoverable */ /* Added in POSIX-2008 */ + E_POSIX_ENOTSOCK, /* Not a socket */ + E_POSIX_ENOTSUP, /* Not supported (may be the same value as [EOPNOTSUPP]) */ + E_POSIX_ENOTTY, /* Inappropriate I/O control operation */ + E_POSIX_ENXIO, /* No such device or address */ + E_POSIX_EOPNOTSUPP, /* Operation not supported on socket (may be the same value as [ENOTSUP]) */ + E_POSIX_EOVERFLOW, /* Value too large to be stored in data type */ + E_POSIX_EOWNERDEAD, /* Previous owner died */ /* Added in POSIX-2008 */ + E_POSIX_EPERM, /* Operation not permitted */ + E_POSIX_EPIPE, /* Broken pipe */ + E_POSIX_EPROTO, /* Protocol error */ + E_POSIX_EPROTONOSUPPORT, /* Protocol not supported */ + E_POSIX_EPROTOTYPE, /* Protocol wrong type for socket */ +#define E_POSIX_ERANGE E_STDC_ERANGE /* Result too large */ + E_POSIX_EROFS, /* Read-only file system */ + E_POSIX_ESOCKTNOSUPPORT, /* Socket type not supported */ + E_POSIX_ESPIPE, /* Invalid seek */ + E_POSIX_ESRCH, /* No such process */ + E_POSIX_ESTALE, /* Reserved */ + E_POSIX_ETIMEDOUT, /* Connection timed out */ + E_POSIX_ETXTBSY, /* Text file busy */ + E_POSIX_EWOULDBLOCK, /* Operation would block (may be the same value as [EAGAIN]) */ + E_POSIX_EXDEV, /* Improper hard link */ + /* End cap */ + E_EUNKNOWN, +} _errnum; + +const char *_errnum_str_sym(_errnum); +const char *_errnum_str_msg(_errnum); + +/* error **********************************************************************/ + +typedef struct { + _errnum num; + char *_msg; +} error; + +#ifdef NDEBUG +#define error_new(ERRNUM, ...) ((error){ \ + .num = ERRNUM , \ + __VA_OPT__(._msg = fmt_asprint(__VA_ARGS__),) \ +}) +#else +#define error_new(ERRNUM, ...) ((error){ \ + .num = ERRNUM, \ + ._msg = fmt_asprint("" __VA_OPT__(,) __VA_ARGS__), \ +}) +#endif + +#define ERROR_NULL ((error){}) +#define ERROR_IS_NULL(err) ((err).num == 0 && (err)._msg == NULL) + +const char *error_msg(error err); +void error_cleanup(error *errptr); +void fmt_print_error(lo_interface fmt_dest w, error err); + +/* or_error ******************************************************************/ + +#define DECLARE_ERROR_OR(TYP) typedef struct { union { TYP TYP; error err; }; bool is_err; } TYP##_or_error +#define ERROR_NEW_VAL(TYP, VAL) ((TYP##_or_error){ .TYP = (VAL), .is_err = false }) +#define ERROR_NEW_ERR(TYP, ERR) ((TYP##_or_error){ .err = (ERR), .is_err = true }) + +/* and_error *****************************************************************/ + +#define DECLARE_ERROR_AND(TYP) typedef struct { TYP TYP; error err; } TYP##_and_error +#define ERROR_AND(TYP, VAL, ERR) ((TYP##_and_error){ .TYP = (VAL), .err = (ERR) }) + +/* some pre-defined types ****************************************************/ + +DECLARE_ERROR_OR(size_t); +DECLARE_ERROR_OR(uint8_t); +DECLARE_ERROR_OR(uint16_t); +DECLARE_ERROR_OR(uint32_t); +DECLARE_ERROR_OR(uint64_t); + +DECLARE_ERROR_AND(size_t); +DECLARE_ERROR_AND(uint8_t); +DECLARE_ERROR_AND(uint16_t); +DECLARE_ERROR_AND(uint32_t); +DECLARE_ERROR_AND(uint64_t); + +#endif /* _LIBMISC_ERROR_H_ */ |