1 /* error.c - Error-management and messaging routines.
2 *
3 * Copyright (C) 1998 Oskar Liljeblad
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #if HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 #include <errno.h> /* C89 */
23 #include <string.h> /* Gnulib/C89 */
24 #include <stdarg.h> /* Gnulib/C89 */
25 #include <stdlib.h> /* Gnulib/C89 */
26 #include <stdio.h> /* Gnulib/C89 */
27 #include "gettext.h" /* Gnulib/Gettext */
28 #define _(s) gettext(s)
29 #include "xvasprintf.h" /* Gnulib */
30 #include "xalloc.h" /* Gnulib */
31 #include "progname.h" /* Gnulib */
32 #include "error.h"
33
34 struct MessageHeader {
35 struct MessageHeader *old;
36 char *message;
37 };
38
39 void (*program_termination_hook)(void) = NULL;
40 static char *error_message = NULL;
41 static struct MessageHeader *message_header = NULL;
42
43 static inline const char *
get_message_header(void)44 get_message_header(void)
45 {
46 if (message_header != NULL)
47 return message_header->message;
48 return program_name;
49 }
50
51 static void
v_warn(const char * msg,va_list ap)52 v_warn(const char *msg, va_list ap)
53 {
54 fprintf(stderr, "%s: ", get_message_header());
55 if (msg != NULL)
56 vfprintf(stderr, msg, ap);
57 fprintf(stderr, "\n");
58 }
59
60 static void
v_warn_errno(const char * msg,va_list ap)61 v_warn_errno(const char *msg, va_list ap)
62 {
63 fprintf(stderr, "%s: ", get_message_header());
64 if (msg != NULL) {
65 vfprintf(stderr, msg, ap);
66 fprintf(stderr, ": ");
67 }
68 fprintf(stderr, "%s\n", strerror(errno));
69 }
70
71 /**
72 * Free all global memory allocated by the error facilities
73 * provided here.
74 */
75 void
free_error(void)76 free_error(void)
77 {
78 struct MessageHeader *hdr;
79
80 for (hdr = message_header; hdr != NULL; hdr = hdr->old) {
81 free(hdr->message);
82 free(hdr);
83 }
84 if (error_message != NULL)
85 free(error_message);
86 }
87
88 /**
89 * This function should be called when an internal error has
90 * occured. It will display a more verbose message, asking
91 * the user to mail the program author.
92 *
93 * @param msg
94 * Error message.
95 */
96 void
internal_error(const char * msg,...)97 internal_error(const char *msg, ...)
98 {
99 va_list ap;
100
101 va_start(ap, msg);
102 if (program_termination_hook != NULL)
103 program_termination_hook();
104 fprintf(stderr, _("\
105 An internal error has occured. Please report this error by sending the\n\
106 output below to %s.\n\
107 \n\
108 Program: %s\n\
109 Version: %s\n\
110 Error: "), PACKAGE_BUGREPORT, program_name, VERSION);
111 vfprintf(stderr, msg, ap);
112 va_end(ap);
113
114 free_error();
115 exit(1);
116 }
117
118 /**
119 * Terminate the program with an error message.
120 *
121 * @param msg
122 * Error message.
123 */
124 void
die(const char * msg,...)125 die(const char *msg, ...)
126 {
127 va_list ap;
128
129 va_start(ap, msg);
130 if (program_termination_hook != NULL)
131 program_termination_hook();
132 v_warn(msg, ap);
133 va_end(ap);
134
135 free_error();
136 exit(1);
137 }
138
139 /**
140 * Terminate the program with an error message and
141 * the current error in `errno'.
142 *
143 * @param msg
144 * Error message, or NULL if only the error in `errno'
145 * should be printed.
146 */
147 void
die_errno(const char * msg,...)148 die_errno(const char *msg, ...)
149 {
150 va_list ap;
151
152 va_start(ap, msg);
153 if (program_termination_hook != NULL)
154 program_termination_hook();
155 v_warn_errno(msg, ap);
156 va_end(ap);
157
158 free_error();
159 exit(1);
160 }
161
162 /**
163 * Write a warning message to standard error.
164 *
165 * @param msg
166 * The message.
167 */
168 void
warn(const char * msg,...)169 warn(const char *msg, ...)
170 {
171 va_list ap;
172
173 va_start(ap, msg);
174 v_warn(msg, ap);
175 va_end(ap);
176 }
177
178
179 /**
180 * Write an error message and the current error in `errno'.
181 *
182 * @param msg
183 * Error message, or NULL if only the error in `errno'
184 * should be printed.
185 */
186 void
warn_errno(const char * msg,...)187 warn_errno(const char *msg, ...)
188 {
189 va_list ap;
190
191 va_start(ap, msg);
192 v_warn_errno(msg, ap);
193 va_end(ap);
194 }
195
196 /**
197 * Set the current message header.
198 */
199 void
set_message_header(const char * msg,...)200 set_message_header(const char *msg, ...)
201 {
202 va_list ap;
203 struct MessageHeader *hdr;
204
205 hdr = malloc(sizeof(struct MessageHeader));
206 if (hdr == NULL)
207 xalloc_die();
208 hdr->old = message_header;
209 va_start(ap, msg);
210 if (vasprintf(&hdr->message, msg, ap) < 0)
211 xalloc_die();
212 message_header = hdr;
213 va_end(ap);
214 }
215
216 /**
217 * Restore the message header to the default.
218 */
219 void
restore_message_header(void)220 restore_message_header(void)
221 {
222 if (message_header != NULL) {
223 struct MessageHeader *old;
224 old = message_header->old;
225 free(message_header->message);
226 free(message_header);
227 message_header = old;
228 }
229 }
230
231 /**
232 * Set a global error message.
233 */
234 void
set_error(const char * format,...)235 set_error(const char *format, ...)
236 {
237 va_list ap;
238
239 if (error_message != NULL)
240 free(error_message);
241
242 if (format != NULL) {
243 va_start(ap, format);
244 if (vasprintf(&error_message, format, ap) < 0)
245 xalloc_die();
246 va_end(ap);
247 } else {
248 error_message = NULL;
249 }
250 }
251
252 /**
253 * Return the global error message.
254 * The returned value cannot be modified and should never
255 * be freed.
256 */
257 const char *
get_error(void)258 get_error(void)
259 {
260 return error_message;
261 }
262
263 /**
264 * Remove and return the global error message.
265 * The returned value may be modified and should
266 * be freed when no longer needed.
267 */
268 char *
remove_error(void)269 remove_error(void)
270 {
271 char *msg = error_message;
272 error_message = NULL;
273 return msg;
274 }
275
276 /**
277 * Die printing the current error message.
278 */
279 void
die_error(void)280 die_error(void)
281 {
282 if (program_termination_hook != NULL)
283 program_termination_hook();
284 warn(error_message);
285 free_error();
286 exit(1);
287 }
288