4 error.c - error reporting code for Imager
9 int new_fatal; // non-zero if errors are fatal
10 int old_fatal = i_set_failure_fatal(new_fatal);
11 i_set_argv0("name of your program");
12 extern void error_cb(char const *);
14 old_ecb = i_set_error_cb(error_cb);
16 extern void failed_cb(char **errors);
17 old_fcb = i_set_failed_cb(failed_cb);
18 if (!i_something(...)) {
19 char **errors = i_errors();
23 undef_int i_something(...) {
25 if (!some_lower_func(...)) {
26 return i_failed("could not something");
30 undef_int some_lower_func(...) {
31 if (somethingelse_failed()) {
32 i_push_error("could not somethingelse");
40 This module provides the C level error handling functionality for
43 A few functions return or pass in an i_errmsg *, this is list of error
44 structures, terminated by an entry with a NULL msg value, each of
45 which contains a msg and an error code. Even though these aren't
46 passed as i_errmsg const * pointers, don't modify the strings
49 The interface as currently defined isn't thread safe, unfortunately.
51 This code uses Imager's mymalloc() for memory allocation, so out of
52 memory errors are I<always> fatal.
56 These functions form the interface that a user of Imager sees (from
57 C). The Perl level won't use all of this.
68 /* we never actually use the last item - it's the NULL terminator */
70 i_errmsg error_stack[ERRSTK];
71 int error_sp = ERRSTK - 1;
72 /* we track the amount of space used each string, so we don't reallocate
73 space unless we need to.
74 This also means that a memory tracking library may see the memory
75 allocated for this as a leak. */
76 int error_space[ERRSTK];
78 static i_error_cb error_cb;
79 static i_failed_cb failed_cb;
80 static int failures_fatal;
84 =item i_set_argv0(char const *program)
86 Sets the name of the program to be displayed in fatal error messages.
88 The simplest way to use this is just:
92 when your program starts.
94 void i_set_argv0(char const *name) {
98 dupl = mymalloc(strlen(name)+1);
106 =item i_set_failure_fatal(int failure_fatal)
108 If failure_fatal is non-zero then any future failures will result in
109 Imager exiting your program with a message describing the failure.
111 Returns the previous setting.
115 int i_set_failures_fatal(int fatal) {
116 int old = failures_fatal;
117 failures_fatal = fatal;
123 =item i_set_error_cb(i_error_cb)
125 Sets a callback function that is called each time an error is pushed
126 onto the error stack.
128 Returns the previous callback.
130 i_set_failed_cb() is probably more useful.
134 i_error_cb i_set_error_cb(i_error_cb cb) {
135 i_error_cb old = error_cb;
142 =item i_set_failed_cb(i_failed_cb cb)
144 Sets a callback function that is called each time an Imager function
147 Returns the previous callback.
151 i_failed_cb i_set_failed_cb(i_failed_cb cb) {
152 i_failed_cb old = failed_cb;
161 Returns a pointer to the first element of an array of error messages,
162 terminated by a NULL pointer. The highest level message is first.
166 i_errmsg *i_errors() {
167 return error_stack + error_sp;
173 =head1 INTERNAL FUNCTIONS
175 These functions are called by Imager to report errors through the
178 It may be desirable to have functions to mark the stack and reset to
183 =item i_clear_error()
185 Called by any imager function before doing any other processing.
188 void i_clear_error() {
189 #ifdef IMAGER_DEBUG_MALLOC
192 for (i = 0; i < ERRSTK; ++i) {
193 if (error_space[i]) {
194 myfree(error_stack[i].msg);
195 error_stack[i].msg = NULL;
204 =item i_push_error(int code, char const *msg)
206 Called by an imager function to push an error message onto the stack.
208 No message is pushed if the stack is full (since this means someone
209 forgot to call i_clear_error(), or that a function that doesn't do
210 error handling is calling function that does.).
214 void i_push_error(int code, char const *msg) {
215 int size = strlen(msg)+1;
218 /* bad, bad programmer */
222 if (error_space[error_sp] < size) {
223 if (error_stack[error_sp].msg)
224 myfree(error_stack[error_sp].msg);
225 /* memory allocated on the following line is only ever release when
226 we need a bigger string */
227 error_stack[error_sp].msg = mymalloc(size);
228 error_space[error_sp] = size;
230 strcpy(error_stack[error_sp].msg, msg);
231 error_stack[error_sp].code = code;
238 =item i_push_errorvf(int code, char const *fmt, va_list ap)
240 Intended for use by higher level functions, takes a varargs pointer
241 and a format to produce the finally pushed error message.
245 void i_push_errorvf(int code, char const *fmt, va_list ap) {
247 #if defined(_MSC_VER)
248 _vsnprintf(buf, sizeof(buf), fmt, ap);
250 /* is there a way to detect vsnprintf()?
251 for this and other functions we need some mechanism to handle
252 detection (like perl's Configure, or autoconf)
254 vsprintf(buf, fmt, ap);
256 i_push_error(code, buf);
260 =item i_push_errorf(int code, char const *fmt, ...)
262 A version of i_push_error() that does printf() like formating.
266 void i_push_errorf(int code, char const *fmt, ...) {
269 i_push_errorvf(code, fmt, ap);
274 =item i_failed(char const *msg)
276 Called by Imager code to indicate that a top-level has failed.
278 msg can be NULL, in which case no error is pushed.
280 Calls the current failed callback, if any.
282 Aborts the program with an error, if failures have been set to be fatal.
284 Returns zero if it does not abort.
288 int i_failed(int code, char const *msg) {
290 i_push_error(code, msg);
292 failed_cb(error_stack + error_sp);
293 if (failures_fatal) {
295 int total; /* total length of error messages */
296 char *full; /* full message for logging */
298 fprintf(stderr, "%s: ", argv0);
299 fputs("error:\n", stderr);
301 while (error_stack[sp].msg) {
302 fprintf(stderr, " %s\n", error_stack[sp].msg);
305 /* we want to log the error too, build an error message to hand to
307 total = 1; /* remember the NUL */
308 for (sp = error_sp; error_stack[sp].msg; ++sp) {
309 total += strlen(error_stack[sp].msg) + 2;
311 full = mymalloc(total);
313 /* just quit, at least it's on stderr */
317 for (sp = error_sp; error_stack[sp].msg; ++sp) {
318 strcat(full, error_stack[sp].msg);
321 /* lose the extra ": " */
322 full[strlen(full)-2] = '\0';
323 m_fatal(EXIT_FAILURE, "%s", full);
334 This interface isn't thread safe.
338 Tony Cook <tony@develop-help.com>
340 Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>