basic clean up of Makefile.PL
[imager.git] / error.c
CommitLineData
606237f9
TC
1/*
2=head1 NAME
3
4error.c - error reporting code for Imager
5
6=head1 SYNOPSIS
7
8 // user code:
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 *);
13 i_error_cb old_ecb;
14 old_ecb = i_set_error_cb(error_cb);
15 i_failed_cb old_fcb;
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();
20 }
21
22 // imager code:
23 undef_int i_something(...) {
24 i_clear_error();
25 if (!some_lower_func(...)) {
26 return i_failed("could not something");
27 }
28 return 1;
29 }
30 undef_int some_lower_func(...) {
31 if (somethingelse_failed()) {
32 i_push_error("could not somethingelse");
33 return 0;
34 }
35 return 1;
36 }
37
38=head1 DESCRIPTION
39
40This module provides the C level error handling functionality for
41Imager.
42
c5cf7614
TC
43A few functions return or pass in an i_errmsg *, this is list of error
44structures, terminated by an entry with a NULL msg value, each of
45which contains a msg and an error code. Even though these aren't
46passed as i_errmsg const * pointers, don't modify the strings
47or the pointers.
606237f9
TC
48
49The interface as currently defined isn't thread safe, unfortunately.
50
51This code uses Imager's mymalloc() for memory allocation, so out of
52memory errors are I<always> fatal.
53
54=head1 INTERFACE
55
56These functions form the interface that a user of Imager sees (from
57C). The Perl level won't use all of this.
58
59=over
60
61=cut
62*/
63
92bda632 64#include "imager.h"
606237f9
TC
65#include <stdio.h>
66#include <stdlib.h>
67
68/* we never actually use the last item - it's the NULL terminator */
69#define ERRSTK 20
b33c08f8
TC
70static i_errmsg error_stack[ERRSTK];
71static int error_sp = ERRSTK - 1;
606237f9
TC
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. */
b33c08f8 76static int error_space[ERRSTK];
606237f9
TC
77
78static i_error_cb error_cb;
79static i_failed_cb failed_cb;
80static int failures_fatal;
81static char *argv0;
82
83/*
84=item i_set_argv0(char const *program)
85
86Sets the name of the program to be displayed in fatal error messages.
87
88The simplest way to use this is just:
89
90 i_set_argv0(argv[0]);
91
92when your program starts.
93*/
94void i_set_argv0(char const *name) {
c5cf7614 95 char *dupl;
606237f9
TC
96 if (!name)
97 return;
f0960b14
TC
98 /* if the user has an existing string of MAXINT length then
99 the system is broken anyway */
100 dupl = mymalloc(strlen(name)+1); /* check 17jul05 tonyc */
606237f9
TC
101 strcpy(dupl, name);
102 if (argv0)
103 myfree(argv0);
104 argv0 = dupl;
105}
106
107/*
108=item i_set_failure_fatal(int failure_fatal)
109
110If failure_fatal is non-zero then any future failures will result in
111Imager exiting your program with a message describing the failure.
112
113Returns the previous setting.
114
115=cut
116*/
117int i_set_failures_fatal(int fatal) {
118 int old = failures_fatal;
119 failures_fatal = fatal;
120
121 return old;
122}
123
124/*
125=item i_set_error_cb(i_error_cb)
126
127Sets a callback function that is called each time an error is pushed
128onto the error stack.
129
130Returns the previous callback.
131
132i_set_failed_cb() is probably more useful.
133
134=cut
135*/
136i_error_cb i_set_error_cb(i_error_cb cb) {
137 i_error_cb old = error_cb;
138 error_cb = cb;
139
140 return old;
141}
142
143/*
144=item i_set_failed_cb(i_failed_cb cb)
145
146Sets a callback function that is called each time an Imager function
147fails.
148
149Returns the previous callback.
150
151=cut
152*/
153i_failed_cb i_set_failed_cb(i_failed_cb cb) {
154 i_failed_cb old = failed_cb;
155 failed_cb = cb;
156
157 return old;
158}
159
160/*
161=item i_errors()
162
163Returns a pointer to the first element of an array of error messages,
164terminated by a NULL pointer. The highest level message is first.
165
166=cut
167*/
c5cf7614 168i_errmsg *i_errors() {
606237f9
TC
169 return error_stack + error_sp;
170}
171
172/*
173=back
174
175=head1 INTERNAL FUNCTIONS
176
177These functions are called by Imager to report errors through the
178above interface.
179
180It may be desirable to have functions to mark the stack and reset to
181the mark.
182
183=over
184
185=item i_clear_error()
6cfee9d1 186=synopsis i_clear_error();
92bda632
TC
187=category Error handling
188
189Clears the error stack.
190
5715f7c3 191Called by any Imager function before doing any other processing.
606237f9 192
92bda632
TC
193=cut
194*/
606237f9 195void i_clear_error() {
cd4b0b20
TC
196#ifdef IMAGER_DEBUG_MALLOC
197 int i;
198
199 for (i = 0; i < ERRSTK; ++i) {
200 if (error_space[i]) {
201 myfree(error_stack[i].msg);
202 error_stack[i].msg = NULL;
203 error_space[i] = 0;
204 }
205 }
206#endif
606237f9
TC
207 error_sp = ERRSTK-1;
208}
209
210/*
faa9b3e7 211=item i_push_error(int code, char const *msg)
6cfee9d1
TC
212=synopsis i_push_error(0, "Yep, it's broken");
213=synopsis i_push_error(errno, "Error writing");
92bda632
TC
214=category Error handling
215
6cfee9d1 216Called by an Imager function to push an error message onto the stack.
606237f9
TC
217
218No message is pushed if the stack is full (since this means someone
219forgot to call i_clear_error(), or that a function that doesn't do
220error handling is calling function that does.).
221
222=cut
223*/
c5cf7614 224void i_push_error(int code, char const *msg) {
8d14daab 225 size_t size = strlen(msg)+1;
606237f9
TC
226
227 if (error_sp <= 0)
228 /* bad, bad programmer */
229 return;
230
231 --error_sp;
232 if (error_space[error_sp] < size) {
c5cf7614
TC
233 if (error_stack[error_sp].msg)
234 myfree(error_stack[error_sp].msg);
f0960b14 235 /* memory allocated on the following line is only ever released when
606237f9 236 we need a bigger string */
f0960b14
TC
237 /* size is size (len+1) of an existing string, overflow would mean
238 the system is broken anyway */
239 error_stack[error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
606237f9
TC
240 error_space[error_sp] = size;
241 }
c5cf7614
TC
242 strcpy(error_stack[error_sp].msg, msg);
243 error_stack[error_sp].code = code;
606237f9
TC
244
245 if (error_cb)
c5cf7614
TC
246 error_cb(code, msg);
247}
248
249/*
5715f7c3 250=item i_push_errorvf(int C<code>, char const *C<fmt>, va_list C<ap>)
c5cf7614 251
92bda632
TC
252=category Error handling
253
c5cf7614
TC
254Intended for use by higher level functions, takes a varargs pointer
255and a format to produce the finally pushed error message.
256
6cfee9d1
TC
257Does not support perl specific format codes.
258
c5cf7614
TC
259=cut
260*/
261void i_push_errorvf(int code, char const *fmt, va_list ap) {
262 char buf[1024];
263#if defined(_MSC_VER)
264 _vsnprintf(buf, sizeof(buf), fmt, ap);
265#else
266 /* is there a way to detect vsnprintf()?
267 for this and other functions we need some mechanism to handle
268 detection (like perl's Configure, or autoconf)
269 */
270 vsprintf(buf, fmt, ap);
271#endif
272 i_push_error(code, buf);
273}
274
275/*
276=item i_push_errorf(int code, char const *fmt, ...)
6cfee9d1 277=synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
92bda632
TC
278=category Error handling
279
5715f7c3 280A version of i_push_error() that does printf() like formatting.
c5cf7614 281
6cfee9d1
TC
282Does not support perl specific format codes.
283
c5cf7614
TC
284=cut
285*/
286void i_push_errorf(int code, char const *fmt, ...) {
287 va_list ap;
288 va_start(ap, fmt);
289 i_push_errorvf(code, fmt, ap);
290 va_end(ap);
606237f9
TC
291}
292
f0960b14
TC
293#ifdef IMAGER_I_FAILED
294#error "This isn't used and is untested"
295
606237f9
TC
296/*
297=item i_failed(char const *msg)
298
299Called by Imager code to indicate that a top-level has failed.
300
c5cf7614 301msg can be NULL, in which case no error is pushed.
606237f9
TC
302
303Calls the current failed callback, if any.
304
305Aborts the program with an error, if failures have been set to be fatal.
306
307Returns zero if it does not abort.
308
309=cut
310*/
c5cf7614 311int i_failed(int code, char const *msg) {
606237f9 312 if (msg)
c5cf7614 313 i_push_error(code, msg);
606237f9
TC
314 if (failed_cb)
315 failed_cb(error_stack + error_sp);
316 if (failures_fatal) {
c5cf7614 317 int sp;
8d14daab 318 size_t total; /* total length of error messages */
c5cf7614 319 char *full; /* full message for logging */
606237f9
TC
320 if (argv0)
321 fprintf(stderr, "%s: ", argv0);
322 fputs("error:\n", stderr);
c5cf7614
TC
323 sp = error_sp;
324 while (error_stack[sp].msg) {
a743c0a6 325 fprintf(stderr, " %s\n", error_stack[sp].msg);
c5cf7614
TC
326 ++sp;
327 }
328 /* we want to log the error too, build an error message to hand to
b1e96952 329 i_fatal() */
c5cf7614
TC
330 total = 1; /* remember the NUL */
331 for (sp = error_sp; error_stack[sp].msg; ++sp) {
8d14daab
TC
332 size_t new_total += strlen(error_stack[sp].msg) + 2;
333 if (new_total < total) {
334 /* overflow, somehow */
335 break;
336 }
c5cf7614 337 }
a6c47345 338 full = mymalloc(total);
c5cf7614
TC
339 if (!full) {
340 /* just quit, at least it's on stderr */
341 exit(EXIT_FAILURE);
342 }
343 *full = 0;
344 for (sp = error_sp; error_stack[sp].msg; ++sp) {
345 strcat(full, error_stack[sp].msg);
346 strcat(full, ": ");
606237f9 347 }
c5cf7614
TC
348 /* lose the extra ": " */
349 full[strlen(full)-2] = '\0';
b1e96952 350 i_fatal(EXIT_FAILURE, "%s", full);
606237f9
TC
351 }
352
353 return 0;
354}
355
f0960b14
TC
356#endif
357
b3afeed5
TC
358/*
359=item im_assert_fail(file, line, message)
360
361Called when an im_assert() assertion fails.
362
363=cut
364*/
365
366void
367im_assert_fail(char const *file, int line, char const *message) {
368 fprintf(stderr, "Assertion failed line %d file %s: %s\n",
369 line, file, message);
370 exit(EXIT_FAILURE);
371}
372
606237f9
TC
373/*
374=back
375
376=head1 BUGS
377
378This interface isn't thread safe.
379
380=head1 AUTHOR
381
382Tony Cook <tony@develop-help.com>
383
384Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>
385
386=cut
387*/