summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/ntux/ntux.h23
-rw-r--r--project/common.mk6
-rw-r--r--project/headers.mk2
-rw-r--r--project/tree.mk1
-rw-r--r--src/driver/ntux_amain.c1
-rw-r--r--src/internal/ntux_driver_impl.h28
-rw-r--r--src/internal/ntux_errinfo_impl.c66
-rw-r--r--src/internal/ntux_errinfo_impl.h96
-rw-r--r--src/internal/ntux_nolibc_impl.h2
-rw-r--r--src/internal/ntux_ntaio_impl.c5
-rw-r--r--src/internal/ntux_strerr_impl.c165
-rw-r--r--src/internal/ntux_strerr_impl.h6
-rw-r--r--src/output/ntux_output_error.c217
13 files changed, 618 insertions, 0 deletions
diff --git a/include/ntux/ntux.h b/include/ntux/ntux.h
index 7e9ca52..12cba1e 100644
--- a/include/ntux/ntux.h
+++ b/include/ntux/ntux.h
@@ -32,6 +32,23 @@ extern "C" {
#define NTUX_DRIVER_VERSION 0x0010
#define NTUX_DRIVER_DRY_RUN 0x0020
+#define NTUX_DRIVER_ANNOTATE_ALWAYS 0x10000000
+#define NTUX_DRIVER_ANNOTATE_NEVER 0x20000000
+#define NTUX_DRIVER_ANNOTATE_FULL 0x40000000
+
+/* error flags */
+#define NTUX_ERROR_TOP_LEVEL 0x0001
+#define NTUX_ERROR_NESTED 0x0002
+#define NTUX_ERROR_CHILD 0x0004
+#define NTUX_ERROR_CUSTOM 0x0008
+#define NTUX_ERROR_NATIVE 0x0010
+
+enum ntux_custom_error {
+ NTUX_ERR_FLOW_ERROR,
+ NTUX_ERR_FLEE_ERROR,
+ NTUX_ERR_LDSO_INIT,
+};
+
enum ntux_cmd {
NTUX_CMD_DEFAULT,
NTUX_CMD_STAT,
@@ -72,6 +89,11 @@ struct ntux_driver_ctx {
void * any;
};
+struct ntux_unit_ctx {
+ const char * const * path;
+ void * any;
+};
+
/* package info */
ntux_api const struct ntux_source_version * ntux_source_version(void);
@@ -82,6 +104,7 @@ ntux_api void ntux_free_driver_ctx (struct ntux_driver_ctx *);
/* utility api */
ntux_api int ntux_main (int, char **, char **);
+ntux_api int ntux_output_error_vector (const struct ntux_driver_ctx *);
#ifdef __cplusplus
}
diff --git a/project/common.mk b/project/common.mk
index c1491b3..1be73a6 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -5,9 +5,14 @@ DRIVER_SRCS = \
INTERNAL_SRCS = \
src/internal/nolibc/ntux_compiler.c \
+ src/internal/ntux_errinfo_impl.c \
src/internal/ntux_memfn_impl.c \
src/internal/ntux_nolibc_impl.c \
src/internal/ntux_ntaio_impl.c \
+ src/internal/ntux_strerr_impl.c \
+
+OUTPUT_SRCS = \
+ src/output/ntux_output_error.c \
APP_SRCS = \
src/ntux.c
@@ -15,3 +20,4 @@ APP_SRCS = \
COMMON_SRCS = \
$(DRIVER_SRCS) \
$(INTERNAL_SRCS) \
+ $(OUTPUT_SRCS) \
diff --git a/project/headers.mk b/project/headers.mk
index c47901c..05d9d25 100644
--- a/project/headers.mk
+++ b/project/headers.mk
@@ -5,8 +5,10 @@ API_HEADERS = \
INTERNAL_HEADERS = \
$(SOURCE_DIR)/src/internal/argv/argv.h \
$(SOURCE_DIR)/src/internal/$(PACKAGE)_driver_impl.h \
+ $(SOURCE_DIR)/src/internal/$(PACKAGE)_errinfo_impl.h \
$(SOURCE_DIR)/src/internal/$(PACKAGE)_init_impl.h \
$(SOURCE_DIR)/src/internal/$(PACKAGE)_memfn_impl.h \
$(SOURCE_DIR)/src/internal/$(PACKAGE)_nolibc_impl.h \
+ $(SOURCE_DIR)/src/internal/$(PACKAGE)_strerr_impl.h \
ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS)
diff --git a/project/tree.mk b/project/tree.mk
index 2a78989..9f0d99e 100644
--- a/project/tree.mk
+++ b/project/tree.mk
@@ -5,5 +5,6 @@ tree.tag:
mkdir -p src/internal
mkdir -p src/internal/nolibc
mkdir -p src/logic
+ mkdir -p src/output
mkdir -p src/skin
touch tree.tag
diff --git a/src/driver/ntux_amain.c b/src/driver/ntux_amain.c
index 6b9acf4..11741c9 100644
--- a/src/driver/ntux_amain.c
+++ b/src/driver/ntux_amain.c
@@ -57,6 +57,7 @@ static void ntux_perform_unit_actions(
static int ntux_exit(struct ntux_driver_ctx * dctx, int ret)
{
+ ntux_output_error_vector(dctx);
ntux_free_driver_ctx(dctx);
return ret;
}
diff --git a/src/internal/ntux_driver_impl.h b/src/internal/ntux_driver_impl.h
index 6c635de..38d10cc 100644
--- a/src/internal/ntux_driver_impl.h
+++ b/src/internal/ntux_driver_impl.h
@@ -26,11 +26,39 @@ struct ntux_driver_ctx_impl {
struct ntux_common_ctx cctx;
struct ntux_driver_ctx ctx;
struct __psx_context xctx;
+ const struct ntux_unit_ctx *euctx;
const char * eunit;
struct ntux_error_info ** errinfp;
struct ntux_error_info ** erricap;
struct ntux_error_info * erriptr[64];
struct ntux_error_info erribuf[64];
+ char errsbuf[28];
+ int errcode;
};
+
+static inline struct ntux_driver_ctx_impl * ntux_get_driver_ictx(const struct ntux_driver_ctx * dctx)
+{
+ uintptr_t addr;
+
+ if (dctx) {
+ addr = (uintptr_t)dctx - offsetof(struct ntux_driver_ctx_impl,ctx);
+ return (struct ntux_driver_ctx_impl *)addr;
+ }
+
+ return 0;
+}
+
+static inline void ntux_driver_set_ectx(
+ const struct ntux_driver_ctx * dctx,
+ const struct ntux_unit_ctx * uctx,
+ const char * unit)
+{
+ struct ntux_driver_ctx_impl * ictx;
+
+ ictx = ntux_get_driver_ictx(dctx);
+ ictx->euctx = uctx;
+ ictx->eunit = unit;
+}
+
#endif
diff --git a/src/internal/ntux_errinfo_impl.c b/src/internal/ntux_errinfo_impl.c
new file mode 100644
index 0000000..2c21663
--- /dev/null
+++ b/src/internal/ntux_errinfo_impl.c
@@ -0,0 +1,66 @@
+/***********************************************************/
+/* ntux: native translation und extension */
+/* Copyright (C) 2016--2018 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
+/***********************************************************/
+
+#include <ntux/ntux.h>
+#include "ntux_driver_impl.h"
+#include "ntux_errinfo_impl.h"
+
+int ntux_errno(const struct ntux_driver_ctx * dctx)
+{
+ struct ntux_driver_ctx_impl * ictx;
+ ictx = ntux_get_driver_ictx(dctx);
+ return ictx->errcode;
+}
+
+int ntux_errno_set(
+ const struct ntux_driver_ctx * dctx,
+ int esyscode)
+{
+ struct ntux_driver_ctx_impl * ictx;
+
+ ictx = ntux_get_driver_ictx(dctx);
+ ictx->errcode = (esyscode < 0)
+ ? -esyscode
+ : esyscode;
+
+ return esyscode;
+}
+
+int ntux_record_error(
+ const struct ntux_driver_ctx * dctx,
+ int esyscode,
+ int elibcode,
+ const char * efunction,
+ int eline,
+ unsigned eflags,
+ void * eany)
+{
+ struct ntux_driver_ctx_impl * ictx;
+ struct ntux_error_info * erri;
+
+ ictx = ntux_get_driver_ictx(dctx);
+
+ if (ictx->errinfp == ictx->erricap)
+ return -1;
+
+ *ictx->errinfp = &ictx->erribuf[ictx->errinfp - ictx->erriptr];
+ erri = *ictx->errinfp;
+
+ erri->euctx = ictx->euctx;
+ erri->eunit = ictx->eunit;
+
+ erri->edctx = dctx;
+ erri->esyscode = esyscode;
+ erri->elibcode = elibcode;
+ erri->efunction = efunction;
+ erri->eline = eline;
+ erri->eflags = eflags;
+ erri->eany = eany;
+
+ ictx->errinfp++;
+
+ return -1;
+}
diff --git a/src/internal/ntux_errinfo_impl.h b/src/internal/ntux_errinfo_impl.h
new file mode 100644
index 0000000..1d3b527
--- /dev/null
+++ b/src/internal/ntux_errinfo_impl.h
@@ -0,0 +1,96 @@
+/***********************************************************/
+/* ntux: native translation und extension */
+/* Copyright (C) 2016--2018 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
+/***********************************************************/
+
+#include <ntux/ntux.h>
+
+int ntux_errno(const struct ntux_driver_ctx *);
+
+int ntux_errno_set(
+ const struct ntux_driver_ctx *,
+ int esyscode);
+
+int ntux_record_error(
+ const struct ntux_driver_ctx *,
+ int esyscode,
+ int elibcode,
+ const char * efunction,
+ int eline,
+ unsigned eflags,
+ void * eany);
+
+#define NTUX_SYSTEM_ERROR(dctx) \
+ ntux_record_error( \
+ dctx, \
+ ntux_errno(dctx), \
+ 0, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL, \
+ 0)
+
+#define NTUX_BUFFER_ERROR(dctx) \
+ ntux_record_error( \
+ dctx, \
+ ENOBUFS, \
+ 0, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL, \
+ 0)
+
+#define NTUX_SPAWN_ERROR(dctx) \
+ ntux_record_error( \
+ dctx, \
+ ntux_errno(dctx), \
+ 0, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL \
+ | (ntux_errno(dctx) ? 0 \
+ : NTUX_ERROR_CHILD), \
+ 0)
+
+#define NTUX_FILE_ERROR(dctx) \
+ ntux_record_error( \
+ dctx, \
+ EIO, \
+ 0, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL, \
+ 0)
+
+#define NTUX_CUSTOM_ERROR(dctx,elibcode) \
+ ntux_record_error( \
+ dctx, \
+ 0, \
+ elibcode, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL \
+ | NTUX_ERROR_CUSTOM, \
+ 0)
+
+#define NTUX_NATIVE_ERROR(dctx,elibcode) \
+ ntux_record_error( \
+ dctx, \
+ 0, \
+ elibcode, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_TOP_LEVEL \
+ | NTUX_ERROR_NATIVE, \
+ 0)
+
+#define NTUX_NESTED_ERROR(dctx) \
+ ntux_record_error( \
+ dctx, \
+ 0, \
+ 0, \
+ __func__, \
+ __LINE__, \
+ NTUX_ERROR_NESTED, \
+ 0)
diff --git a/src/internal/ntux_nolibc_impl.h b/src/internal/ntux_nolibc_impl.h
index d048bd4..a12b848 100644
--- a/src/internal/ntux_nolibc_impl.h
+++ b/src/internal/ntux_nolibc_impl.h
@@ -5,6 +5,7 @@
#define fileno ntux_fileno
#define fputs ntux_fputs
+#define fflush ntux_fflush
#define fprintf ntux_fprintf
#define sprintf ntux_sprintf
#define snprintf ntux_snprintf
@@ -35,6 +36,7 @@ int ntux_sprintf(char * str, const char * fmt, ...);
int ntux_snprintf(char * str, size_t n, const char * fmt, ...);
int ntux_fprintf(FILE *__restrict, const char *__restrict, ...);
int ntux_fputs(const char * str, FILE * file);
+int ntux_fflush(FILE *);
void * ntux_memcpy(void * dst, const void * src, size_t n);
void * memset(void * ch, int c, size_t n);
diff --git a/src/internal/ntux_ntaio_impl.c b/src/internal/ntux_ntaio_impl.c
index 377a833..850a7d7 100644
--- a/src/internal/ntux_ntaio_impl.c
+++ b/src/internal/ntux_ntaio_impl.c
@@ -112,3 +112,8 @@ int ntux_fileno(void * any)
{
return (int)(intptr_t)any;
}
+
+int ntux_fflush(FILE * file)
+{
+ return __sys_fsync((int)(intptr_t)file);
+}
diff --git a/src/internal/ntux_strerr_impl.c b/src/internal/ntux_strerr_impl.c
new file mode 100644
index 0000000..6cb4853
--- /dev/null
+++ b/src/internal/ntux_strerr_impl.c
@@ -0,0 +1,165 @@
+/***********************************************************/
+/* ntux: native translation und extension */
+/* Copyright (C) 2016--2018 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
+/***********************************************************/
+
+#include <psxabi/sys_errno.h>
+
+#include <ntux/ntux.h>
+#include "ntux_driver_impl.h"
+#include "ntux_nolibc_impl.h"
+
+const char * ntux_posix_error_strs[] = {
+ [0] = "EOK",
+ [EPERM] = "EPERM",
+ [ENOENT] = "ENOENT",
+ [ESRCH] = "ESRCH",
+ [EINTR] = "EINTR",
+ [EIO] = "EIO",
+ [ENXIO] = "ENXIO",
+ [E2BIG] = "E2BIG",
+ [ENOEXEC] = "ENOEXEC",
+ [EBADF] = "EBADF",
+ [ECHILD] = "ECHILD",
+ [EAGAIN] = "EAGAIN",
+ [ENOMEM] = "ENOMEM",
+ [EACCES] = "EACCES",
+ [EFAULT] = "EFAULT",
+ [ENOTBLK] = "ENOTBLK",
+ [EBUSY] = "EBUSY",
+ [EEXIST] = "EEXIST",
+ [EXDEV] = "EXDEV",
+ [ENODEV] = "ENODEV",
+ [ENOTDIR] = "ENOTDIR",
+ [EISDIR] = "EISDIR",
+ [EINVAL] = "EINVAL",
+ [ENFILE] = "ENFILE",
+ [EMFILE] = "EMFILE",
+ [ENOTTY] = "ENOTTY",
+ [ETXTBSY] = "ETXTBSY",
+ [EFBIG] = "EFBIG",
+ [ENOSPC] = "ENOSPC",
+ [ESPIPE] = "ESPIPE",
+ [EROFS] = "EROFS",
+ [EMLINK] = "EMLINK",
+ [EPIPE] = "EPIPE",
+ [EDOM] = "EDOM",
+ [ERANGE] = "ERANGE",
+ [EDEADLK] = "EDEADLK",
+ [ENAMETOOLONG] = "ENAMETOOLONG",
+ [ENOLCK] = "ENOLCK",
+ [ENOSYS] = "ENOSYS",
+ [ENOTEMPTY] = "ENOTEMPTY",
+ [ELOOP] = "ELOOP",
+ [ENOMSG] = "ENOMSG",
+ [EIDRM] = "EIDRM",
+ [ECHRNG] = "ECHRNG",
+ [EL2NSYNC] = "EL2NSYNC",
+ [EL3HLT] = "EL3HLT",
+ [EL3RST] = "EL3RST",
+ [ELNRNG] = "ELNRNG",
+ [EUNATCH] = "EUNATCH",
+ [ENOCSI] = "ENOCSI",
+ [EL2HLT] = "EL2HLT",
+ [EBADE] = "EBADE",
+ [EBADR] = "EBADR",
+ [EXFULL] = "EXFULL",
+ [ENOANO] = "ENOANO",
+ [EBADRQC] = "EBADRQC",
+ [EBADSLT] = "EBADSLT",
+ [EBFONT] = "EBFONT",
+ [ENOSTR] = "ENOSTR",
+ [ENODATA] = "ENODATA",
+ [ETIME] = "ETIME",
+ [ENOSR] = "ENOSR",
+ [ENONET] = "ENONET",
+ [ENOPKG] = "ENOPKG",
+ [EREMOTE] = "EREMOTE",
+ [ENOLINK] = "ENOLINK",
+ [EADV] = "EADV",
+ [ESRMNT] = "ESRMNT",
+ [ECOMM] = "ECOMM",
+ [EPROTO] = "EPROTO",
+ [EMULTIHOP] = "EMULTIHOP",
+ [EDOTDOT] = "EDOTDOT",
+ [EBADMSG] = "EBADMSG",
+ [EOVERFLOW] = "EOVERFLOW",
+ [ENOTUNIQ] = "ENOTUNIQ",
+ [EBADFD] = "EBADFD",
+ [EREMCHG] = "EREMCHG",
+ [ELIBACC] = "ELIBACC",
+ [ELIBBAD] = "ELIBBAD",
+ [ELIBSCN] = "ELIBSCN",
+ [ELIBMAX] = "ELIBMAX",
+ [ELIBEXEC] = "ELIBEXEC",
+ [EILSEQ] = "EILSEQ",
+ [ERESTART] = "ERESTART",
+ [ESTRPIPE] = "ESTRPIPE",
+ [EUSERS] = "EUSERS",
+ [ENOTSOCK] = "ENOTSOCK",
+ [EDESTADDRREQ] = "EDESTADDRREQ",
+ [EMSGSIZE] = "EMSGSIZE",
+ [EPROTOTYPE] = "EPROTOTYPE",
+ [ENOPROTOOPT] = "ENOPROTOOPT",
+ [EPROTONOSUPPORT] = "EPROTONOSUPPORT",
+ [ESOCKTNOSUPPORT] = "ESOCKTNOSUPPORT",
+ [EOPNOTSUPP] = "EOPNOTSUPP",
+ [EPFNOSUPPORT] = "EPFNOSUPPORT",
+ [EAFNOSUPPORT] = "EAFNOSUPPORT",
+ [EADDRINUSE] = "EADDRINUSE",
+ [EADDRNOTAVAIL] = "EADDRNOTAVAIL",
+ [ENETDOWN] = "ENETDOWN",
+ [ENETUNREACH] = "ENETUNREACH",
+ [ENETRESET] = "ENETRESET",
+ [ECONNABORTED] = "ECONNABORTED",
+ [ECONNRESET] = "ECONNRESET",
+ [ENOBUFS] = "ENOBUFS",
+ [EISCONN] = "EISCONN",
+ [ENOTCONN] = "ENOTCONN",
+ [ESHUTDOWN] = "ESHUTDOWN",
+ [ETOOMANYREFS] = "ETOOMANYREFS",
+ [ETIMEDOUT] = "ETIMEDOUT",
+ [ECONNREFUSED] = "ECONNREFUSED",
+ [EHOSTDOWN] = "EHOSTDOWN",
+ [EHOSTUNREACH] = "EHOSTUNREACH",
+ [EALREADY] = "EALREADY",
+ [EINPROGRESS] = "EINPROGRESS",
+ [ESTALE] = "ESTALE",
+ [EUCLEAN] = "EUCLEAN",
+ [ENOTNAM] = "ENOTNAM",
+ [ENAVAIL] = "ENAVAIL",
+ [EISNAM] = "EISNAM",
+ [EREMOTEIO] = "EREMOTEIO",
+ [EDQUOT] = "EDQUOT",
+ [ENOMEDIUM] = "ENOMEDIUM",
+ [EMEDIUMTYPE] = "EMEDIUMTYPE",
+ [ECANCELED] = "ECANCELED",
+ [ENOKEY] = "ENOKEY",
+ [EKEYEXPIRED] = "EKEYEXPIRED",
+ [EKEYREVOKED] = "EKEYREVOKED",
+ [EKEYREJECTED] = "EKEYREJECTED",
+ [EOWNERDEAD] = "EOWNERDEAD",
+ [ENOTRECOVERABLE] = "ENOTRECOVERABLE",
+ [ERFKILL] = "ERFKILL",
+ [EHWPOISON] = "EHWPOISON",
+ [EERRORS] = 0};
+
+const char * ntux_strerror(
+ const struct ntux_driver_ctx * dctx,
+ int errno)
+{
+ struct ntux_driver_ctx_impl * ictx;
+
+ if ((errno >= 0) && (errno < EERRORS))
+ return ntux_posix_error_strs[errno];
+
+ ictx = ntux_get_driver_ictx(dctx);
+
+ ntux_sprintf(
+ ictx->errsbuf,
+ "Unknown error %d",
+ errno);
+
+ return ictx->errsbuf;
+}
diff --git a/src/internal/ntux_strerr_impl.h b/src/internal/ntux_strerr_impl.h
new file mode 100644
index 0000000..3f317a7
--- /dev/null
+++ b/src/internal/ntux_strerr_impl.h
@@ -0,0 +1,6 @@
+#ifndef NTUX_STRERR_IMPL_H
+#define NTUX_STRERR_IMPL_H
+
+const char * ntux_strerror(const struct ntux_driver_ctx *, int);
+
+#endif
diff --git a/src/output/ntux_output_error.c b/src/output/ntux_output_error.c
new file mode 100644
index 0000000..47858ab
--- /dev/null
+++ b/src/output/ntux_output_error.c
@@ -0,0 +1,217 @@
+/***********************************************************/
+/* ntux: native translation und extension */
+/* Copyright (C) 2016--2018 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
+/***********************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <psxabi/sys_errno.h>
+
+#include <ntux/ntux.h>
+#include "ntux_driver_impl.h"
+#include "ntux_nolibc_impl.h"
+#include "ntux_strerr_impl.h"
+
+static const char aclr_reset[] = "\x1b[0m";
+static const char aclr_bold[] = "\x1b[1m";
+
+static const char aclr_red[] = "\x1b[31m";
+static const char aclr_green[] = "\x1b[32m";
+static const char aclr_blue[] = "\x1b[34m";
+static const char aclr_magenta[] = "\x1b[35m";
+
+static const char * ntux_output_error_header(const struct ntux_error_info * erri)
+{
+ if (erri->eflags & NTUX_ERROR_CHILD)
+ return "exec error upon";
+
+ else if (erri->eflags & NTUX_ERROR_TOP_LEVEL)
+ return "error logged in";
+
+ else if (erri->eflags & NTUX_ERROR_NESTED)
+ return "< returned to >";
+
+ else
+ return "distorted state";
+}
+
+static const char * ntux_output_unit_header(const struct ntux_error_info * erri)
+{
+ if (!(erri->eflags & NTUX_ERROR_CUSTOM))
+ return "while opening";
+
+ else
+ return "while querying";
+}
+
+static const char * ntux_output_strerror(
+ const struct ntux_driver_ctx * dctx,
+ const struct ntux_error_info * erri)
+{
+ struct ntux_driver_ctx_impl * ictx;
+
+ if (erri->eflags & NTUX_ERROR_NATIVE) {
+ ictx = ntux_get_driver_ictx(dctx);
+ ntux_sprintf(ictx->errsbuf,"system error: 0x%X",erri->elibcode);
+ return ictx->errsbuf;
+ }
+
+ if (erri->eflags & NTUX_ERROR_CUSTOM)
+ return "flow error: unexpected condition or other";
+
+ else if (erri->eflags & NTUX_ERROR_NESTED)
+ return "";
+
+ else if (erri->eflags & NTUX_ERROR_CHILD)
+ return "(see child process error messages)";
+
+ else if (erri->esyscode == ENOBUFS)
+ return "input error: string length exceeds buffer size.";
+
+ else
+ return ntux_strerror(dctx,erri->esyscode);
+}
+
+static int ntux_output_error_record_plain(
+ const struct ntux_driver_ctx * dctx,
+ const struct ntux_error_info * erri)
+{
+ const char * epath;
+ const char * errdesc = ntux_output_strerror(dctx,erri);
+
+ epath = erri->euctx
+ ? *erri->euctx->path
+ : erri->eunit;
+
+ if (epath && !(erri->eflags & NTUX_ERROR_NESTED))
+ if (ntux_fprintf(stderr,"%s: [%s] '%s':\n",
+ dctx->program,
+ ntux_output_unit_header(erri),
+ epath) < 0)
+ return -1;
+
+ if (fprintf(stderr,"%s: %s %s(), line %d%s%s.\n",
+ dctx->program,
+ ntux_output_error_header(erri),
+ erri->efunction,
+ erri->eline,
+ strlen(errdesc) ? ": " : "",
+ errdesc) < 0)
+ return -1;
+
+ return fflush(stderr);
+}
+
+static int ntux_output_error_record_annotated(
+ const struct ntux_driver_ctx * dctx,
+ const struct ntux_error_info * erri)
+{
+ const char * epath;
+ const char * errdesc = ntux_output_strerror(dctx,erri);
+
+ epath = erri->euctx
+ ? *erri->euctx->path
+ : erri->eunit;
+
+ if (epath && !(erri->eflags & NTUX_ERROR_NESTED))
+ if (ntux_fprintf(
+ stderr,
+ "%s%s%s:%s %s[%s]%s %s%s'%s'%s:\n",
+
+ aclr_bold,aclr_magenta,
+ dctx->program,
+ aclr_reset,
+
+ aclr_bold,
+ ntux_output_unit_header(erri),
+ aclr_reset,
+
+ aclr_bold,aclr_red,
+ epath,
+ aclr_reset) < 0)
+ return -1;
+
+ if (fprintf(
+ stderr,
+ "%s%s%s:%s %s%s%s %s%s%s()%s, %s%sline %d%s%s%s%s%s.\n",
+
+ aclr_bold,aclr_magenta,
+ dctx->program,
+ aclr_reset,
+
+ aclr_bold,
+ ntux_output_error_header(erri),
+ aclr_reset,
+
+ aclr_bold,aclr_blue,
+ erri->efunction,
+ aclr_reset,
+
+ aclr_bold,aclr_green,
+ erri->eline,
+ aclr_reset,
+ strlen(errdesc) ? ": " : "",
+
+ aclr_bold,
+ ntux_output_strerror(dctx,erri),
+ aclr_reset) < 0)
+ return -1;
+
+ return fflush(stderr);
+}
+
+int ntux_output_error_record(
+ const struct ntux_driver_ctx * dctx,
+ const struct ntux_error_info * erri)
+{
+ if (dctx->cctx->drvflags & NTUX_DRIVER_ANNOTATE_NEVER)
+ return ntux_output_error_record_plain(dctx,erri);
+
+ else if (dctx->cctx->drvflags & NTUX_DRIVER_ANNOTATE_ALWAYS)
+ return ntux_output_error_record_annotated(dctx,erri);
+
+ else if (isatty(STDERR_FILENO))
+ return ntux_output_error_record_annotated(dctx,erri);
+
+ else
+ return ntux_output_error_record_plain(dctx,erri);
+}
+
+static int ntux_output_error_vector_plain(const struct ntux_driver_ctx * dctx)
+{
+ struct ntux_error_info ** perr;
+
+ for (perr=dctx->errv; *perr; perr++)
+ if (ntux_output_error_record_plain(dctx,*perr))
+ return -1;
+
+ return 0;
+}
+
+static int ntux_output_error_vector_annotated(const struct ntux_driver_ctx * dctx)
+{
+ struct ntux_error_info ** perr;
+
+ for (perr=dctx->errv; *perr; perr++)
+ if (ntux_output_error_record_annotated(dctx,*perr))
+ return -1;
+
+ return 0;
+}
+
+int ntux_output_error_vector(const struct ntux_driver_ctx * dctx)
+{
+ if (dctx->cctx->drvflags & NTUX_DRIVER_ANNOTATE_NEVER)
+ return ntux_output_error_vector_plain(dctx);
+
+ else if (dctx->cctx->drvflags & NTUX_DRIVER_ANNOTATE_ALWAYS)
+ return ntux_output_error_vector_annotated(dctx);
+
+ else if (isatty(STDERR_FILENO))
+ return ntux_output_error_vector_annotated(dctx);
+
+ else
+ return ntux_output_error_vector_plain(dctx);
+}