]> diplodocus.org Git - nmh/blobdiff - sbr/error.c
new.c: Order two return statements to match comment.
[nmh] / sbr / error.c
index 0e02f2abd084cc8baacb651541b7fd2df619475a..5a5808c22f8552ee20fdc52707beac6bf90ac8be 100644 (file)
@@ -1,25 +1,33 @@
-
-/*
- * error.c -- main error handling routines
+/* error.c -- main error handling routines
  *
- * $Id$
+ * This code is Copyright (c) 2002, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
  */
 
 #include <h/mh.h>
 
-#ifdef HAVE_WRITEV
-# include <sys/types.h>
-# include <sys/uio.h>
-#endif
+#include <sys/types.h>
+#include <sys/uio.h>
 
-extern int errno;
 
+/* 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;
 
@@ -29,11 +37,16 @@ advise (char *what, char *fmt, ...)
 }
 
 
-/*
- * print out error message and exit
- */
-void
-adios (char *what, 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;
 
@@ -41,12 +54,28 @@ adios (char *what, 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, ...)
 {
@@ -58,83 +87,66 @@ admonish (char *what, char *fmt, ...)
 }
 
 
-/*
- * main routine for printing error messages.
- *
- * Use writev() if available, for slightly better performance.
- * Why?  Well, there are a couple of reasons.  Primarily, it
- * gives a smoother output...  More importantly though, it's a
- * sexy syscall()...
- */
+/* 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, char *fmt, va_list ap)
+advertise (const char *what, char *tail, const char *fmt, va_list ap)
 {
     int        eindex = errno;
+    char buffer[NMH_BUFSIZ], *err;
+    struct iovec iob[10], *iov;
+    size_t niov;
 
-#ifdef HAVE_WRITEV
-    char buffer[BUFSIZ], err[BUFSIZ];
-    struct iovec iob[20], *iov;
-#endif
+    iov = iob;
 
-    fflush (stdout);
+#define APPEND_IOV(p, len) \
+    iov->iov_base = (p); \
+    iov->iov_len = (len); \
+    iov++
 
-#ifdef HAVE_WRITEV
-    fflush (stderr);
-    iov = iob;
+#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++;
-    writev (fileno (stderr), iob, iov - iob);
-#else
-    if (invo_name && *invo_name)
-       fprintf (stderr, "%s: ", invo_name);
-    vfprintf (stderr, fmt, ap);
+    ADD_LITERAL("\n");
 
-    if (what) {
-       char *s;
-
-       if (*what)
-           fprintf (stderr, " %s: ", what);
-       if ((s = strerror(eindex)))
-           fprintf (stderr, "%s", s);
-       else
-           fprintf (stderr, "Error %d", eindex);
+#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. */
+        }
     }
-    if (tail)
-       fprintf (stderr, ", %s", tail);
-    fputc ('\n', stderr);
-#endif
 }