]> diplodocus.org Git - nmh/blob - sbr/error.c
man/*.man: Use italic for emphasis, not bold or SHOUTING.
[nmh] / sbr / error.c
1
2 /*
3 * error.c -- main error handling routines
4 *
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11
12 #include <sys/types.h>
13 #include <sys/uio.h>
14
15
16 /* inform calls advertise() with no what and no tail.
17 * Thus the simple "[invo_name: ]fmt\n" results. */
18 void inform(char *fmt, ...)
19 {
20 va_list ap;
21
22 va_start(ap, fmt);
23 advertise(NULL, NULL, fmt, ap);
24 va_end(ap);
25 }
26
27
28 /* advise calls advertise() with no tail to print fmt, and perhaps what,
29 * to stderr.
30 * Thus "[invo_name: ]fmt[[ what]: errno]\n" results. */
31 void
32 advise (const char *what, const char *fmt, ...)
33 {
34 va_list ap;
35
36 va_start(ap, fmt);
37 advertise (what, NULL, fmt, ap);
38 va_end(ap);
39 }
40
41
42 /* adios is the same as advise(), but then "ends" the program.
43 * It calls advertise() with no tail to print fmt, and perhaps what, to
44 * stderr, and exits the program with an error status.
45 * Thus "[invo_name: ]fmt[[ what]: errno]\n" results.
46 * The route to exit is via the done function pointer and may not be
47 * straightforward, e.g. longjmp(3), but it must not return to adios().
48 * If it does then it's a bug and adios() will abort(3) as callers do
49 * not expect execution to continue. */
50 void
51 adios (const char *what, const char *fmt, ...)
52 {
53 va_list ap;
54
55 va_start(ap, fmt);
56 advertise (what, NULL, fmt, ap);
57 va_end(ap);
58 done (1);
59 abort();
60 }
61
62
63 /* admonish calls advertise() with a tail indicating the program
64 * continues.
65 * Thus "[invo_name: ]fmt[[ what]: errno], continuing...\n" results. */
66 void
67 admonish (char *what, char *fmt, ...)
68 {
69 va_list ap;
70
71 va_start(ap, fmt);
72 advertise (what, "continuing...", fmt, ap);
73 va_end(ap);
74 }
75
76
77 /* advertise prints fmt and ap to stderr after flushing stdout.
78 * If invo_name isn't NULL or empty then "invo_name: " precedes fmt.
79 * If what isn't NULL or empty then " what" is appended.
80 * If what isn't NULL then ": errno" is appended.
81 * If tail isn't NULL or empty then ", tail" is appended.
82 * A "\n" finishes the output to stderr.
83 * In summary: "[invo_name: ]fmt[[ what]: errno][, tail]\n". */
84 void
85 advertise (const char *what, char *tail, const char *fmt, va_list ap)
86 {
87 int eindex = errno;
88 char buffer[NMH_BUFSIZ], *err;
89 struct iovec iob[10], *iov;
90 size_t niov;
91
92 iov = iob;
93
94 #define APPEND_IOV(p, len) \
95 iov->iov_base = (p); \
96 iov->iov_len = (len); \
97 iov++
98
99 #define ADD_LITERAL(s) APPEND_IOV((s), LEN(s))
100 #define ADD_VAR(s) APPEND_IOV((s), strlen(s))
101
102 if (invo_name && *invo_name) {
103 ADD_VAR(invo_name);
104 ADD_LITERAL(": ");
105 }
106
107 vsnprintf (buffer, sizeof(buffer), fmt, ap);
108 ADD_VAR(buffer);
109 if (what) {
110 if (*what) {
111 ADD_LITERAL(" ");
112 ADD_VAR((void *)what);
113 }
114 ADD_LITERAL(": ");
115 err = strerror(eindex);
116 ADD_VAR(err);
117 }
118 if (tail && *tail) {
119 ADD_LITERAL(", ");
120 ADD_VAR(tail);
121 }
122 ADD_LITERAL("\n");
123
124 #undef ADD_LITERAL
125 #undef ADD_VAR
126
127 niov = iov - iob;
128 assert(niov <= DIM(iob));
129
130 fflush (stdout);
131 fflush (stderr);
132 if (writev(fileno(stderr), iob, niov) == -1) {
133 snprintf(buffer, sizeof buffer, "%s: write stderr failed: %d\n",
134 invo_name && *invo_name ? invo_name : "nmh", errno);
135 if (write(2, buffer, strlen(buffer)) == -1) {
136 /* Ignore. if-statement needed to shut up compiler. */
137 }
138 }
139 }