#include <h/mh.h>
-#ifdef HAVE_WRITEV
-# include <sys/types.h>
-# include <sys/uio.h>
-#endif
+#include <sys/types.h>
+#include <sys/uio.h>
-#include <errno.h>
-
-/*
- * print out error message
- */
+/* advise calls advertise() with no tail to print fmt, and perhaps what,
+ * to stderr. */
void
-advise (char *what, char *fmt, ...)
+advise (const char *what, const char *fmt, ...)
{
va_list ap;
}
-/*
- * print out error message and exit
- */
+/* adios calls advertise() with no tail to print fmt, and perhaps what,
+ * to stderr, and "ends" the program with an error exit status. The
+ * route to exit is via the done function pointer and may not be
+ * straightforward.
+ * FIXME: Document if this function can ever return. If not, perhaps an
+ * abort(3) at the end of the routine would make that more clear. */
void
-adios (char *what, char *fmt, ...)
+adios (const char *what, const char *fmt, ...)
{
va_list ap;
}
-/*
- * admonish the user
- */
+/* admonish calls advertise() with a tail indicating the program
+ * continues. */
void
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, it precedes the output seperated by ": ".
+ * If what isn't NULL, errno as a string is appended.
+ * A non-empty what separates fmt from errno, surrounded by " " and ": ".
+ * BUG: No space separator before errno if what is "".
+ * If tail isn't NULL or empty then ", " and tail are appended
+ * before the finishing "\n".
+ * 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[BUFSIZ], errbuf[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);
+ ADD_LITERAL(": ");
}
- if (!(iov->iov_base = strerror (eindex))) {
+ err = strerror(eindex);
+ if (!err) {
/* this shouldn't happen, but we'll test for it just in case */
- snprintf (err, sizeof(err), "Error %d", eindex);
- iov->iov_base = err;
+ snprintf(errbuf, sizeof(errbuf), "Error %d", eindex);
+ err = errbuf;
}
- iov->iov_len = strlen (iov->iov_base);
- iov++;
+ 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
}