X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/b9e0388a118e84f002ae0da6c7a31bdbd89a73bb..94187a80bd60baab4b9c4b949ad820d730578123:/sbr/error.c diff --git a/sbr/error.c b/sbr/error.c index 184c9509..82850510 100644 --- a/sbr/error.c +++ b/sbr/error.c @@ -1,6 +1,4 @@ - -/* - * error.c -- main error handling routines +/* error.c -- main error handling routines * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -11,13 +9,25 @@ #include #include +#include "h/done.h" +/* inform calls advertise() with no what and no tail. + * Thus the simple "[invo_name: ]fmt\n" results. */ +void inform(char *fmt, ...) +{ + va_list ap; -/* - * print out error message - */ + va_start(ap, fmt); + advertise(NULL, NULL, fmt, ap); + va_end(ap); +} + + +/* advise calls advertise() with no tail to print fmt, and perhaps what, + * to stderr. + * Thus "[invo_name: ]fmt[[ what]: errno]\n" results. */ void -advise (char *what, char *fmt, ...) +advise (const char *what, const char *fmt, ...) { va_list ap; @@ -27,11 +37,16 @@ advise (char *what, char *fmt, ...) } -/* - * print out error message and exit - */ -void -adios (char *what, const char *fmt, ...) +/* adios is the same as advise(), but then "ends" the program. + * It calls advertise() with no tail to print fmt, and perhaps what, to + * stderr, and exits the program with an error status. + * Thus "[invo_name: ]fmt[[ what]: errno]\n" results. + * The route to exit is via the done function pointer and may not be + * straightforward, e.g. longjmp(3), but it must not return to adios(). + * If it does then it's a bug and adios() will abort(3) as callers do + * not expect execution to continue. */ +void NORETURN +adios (const char *what, const char *fmt, ...) { va_list ap; @@ -39,12 +54,28 @@ adios (char *what, const char *fmt, ...) advertise (what, NULL, fmt, ap); va_end(ap); done (1); + abort(); } -/* - * admonish the user - */ +/* die is the same as adios(), but without the what as that's commonly + * NULL. */ +void NORETURN +die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + advertise(NULL, NULL, fmt, ap); + va_end(ap); + done(1); + abort(); +} + + +/* admonish calls advertise() with a tail indicating the program + * continues. + * Thus "[invo_name: ]fmt[[ what]: errno], continuing...\n" results. */ void admonish (char *what, char *fmt, ...) { @@ -56,57 +87,66 @@ admonish (char *what, char *fmt, ...) } -/* - * main routine for printing error messages. - */ +/* advertise prints fmt and ap to stderr after flushing stdout. + * If invo_name isn't NULL or empty then "invo_name: " precedes fmt. + * If what isn't NULL or empty then " what" is appended. + * If what isn't NULL then ": errno" is appended. + * If tail isn't NULL or empty then ", tail" is appended. + * A "\n" finishes the output to stderr. + * In summary: "[invo_name: ]fmt[[ what]: errno][, tail]\n". */ void -advertise (char *what, char *tail, const char *fmt, va_list ap) +advertise (const char *what, char *tail, const char *fmt, va_list ap) { int eindex = errno; - char buffer[BUFSIZ], err[BUFSIZ]; - struct iovec iob[20], *iov; - - fflush (stdout); + char buffer[NMH_BUFSIZ], *err; + struct iovec iob[10], *iov; + size_t niov; - fflush (stderr); iov = iob; +#define APPEND_IOV(p, len) \ + iov->iov_base = (p); \ + iov->iov_len = (len); \ + iov++ + +#define ADD_LITERAL(s) APPEND_IOV((s), LEN(s)) +#define ADD_VAR(s) APPEND_IOV((s), strlen(s)) + if (invo_name && *invo_name) { - iov->iov_len = strlen (iov->iov_base = invo_name); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; + ADD_VAR(invo_name); + ADD_LITERAL(": "); } vsnprintf (buffer, sizeof(buffer), fmt, ap); - iov->iov_len = strlen (iov->iov_base = buffer); - iov++; + ADD_VAR(buffer); if (what) { if (*what) { - iov->iov_len = strlen (iov->iov_base = " "); - iov++; - iov->iov_len = strlen (iov->iov_base = what); - iov++; - iov->iov_len = strlen (iov->iov_base = ": "); - iov++; + ADD_LITERAL(" "); + ADD_VAR((void *)what); } - if (!(iov->iov_base = strerror (eindex))) { - /* this shouldn't happen, but we'll test for it just in case */ - snprintf (err, sizeof(err), "Error %d", eindex); - iov->iov_base = err; - } - iov->iov_len = strlen (iov->iov_base); - iov++; + ADD_LITERAL(": "); + err = strerror(eindex); + ADD_VAR(err); } if (tail && *tail) { - iov->iov_len = strlen (iov->iov_base = ", "); - iov++; - iov->iov_len = strlen (iov->iov_base = tail); - iov++; + ADD_LITERAL(", "); + ADD_VAR(tail); } - iov->iov_len = strlen (iov->iov_base = "\n"); - iov++; - if (writev (fileno (stderr), iob, iov - iob) < 0) { - advise ("stderr", "writev"); + ADD_LITERAL("\n"); + +#undef ADD_LITERAL +#undef ADD_VAR + + niov = iov - iob; + assert(niov <= DIM(iob)); + + fflush (stdout); + fflush (stderr); + if (writev(fileno(stderr), iob, niov) == -1) { + snprintf(buffer, sizeof buffer, "%s: write stderr failed: %d\n", + invo_name && *invo_name ? invo_name : "nmh", errno); + if (write(2, buffer, strlen(buffer)) == -1) { + /* Ignore. if-statement needed to shut up compiler. */ + } } }