eliminate some unused code
[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
74315ca9 64#include "imageri.h"
606237f9
TC
65#include <stdio.h>
66#include <stdlib.h>
67
d03fd5a4 68/*
8b30e240
TC
69=item im_errors(ctx)
70=synopsis i_errmsg *errors = im_errors(aIMCTX);
71=synopsis i_errmsg *errors = i_errors();
606237f9
TC
72
73Returns a pointer to the first element of an array of error messages,
74terminated by a NULL pointer. The highest level message is first.
75
8b30e240
TC
76Also callable as C<i_errors()>.
77
606237f9
TC
78=cut
79*/
74315ca9
TC
80i_errmsg *im_errors(im_context_t ctx) {
81 return ctx->error_stack + ctx->error_sp;
82}
83
606237f9
TC
84/*
85=back
86
87=head1 INTERNAL FUNCTIONS
88
89These functions are called by Imager to report errors through the
90above interface.
91
92It may be desirable to have functions to mark the stack and reset to
93the mark.
94
95=over
96
d03fd5a4 97=item i_clear_error()
6cfee9d1 98=synopsis i_clear_error();
92bda632
TC
99=category Error handling
100
101Clears the error stack.
102
5715f7c3 103Called by any Imager function before doing any other processing.
606237f9 104
92bda632
TC
105=cut
106*/
74315ca9
TC
107
108void
109im_clear_error(im_context_t ctx) {
cd4b0b20
TC
110#ifdef IMAGER_DEBUG_MALLOC
111 int i;
112
74315ca9
TC
113 for (i = 0; i < IM_ERROR_COUNT; ++i) {
114 if (ctx->error_space[i]) {
115 myfree(ctx->error_stack[i].msg);
116 ctx->error_stack[i].msg = NULL;
117 ctx->error_space[i] = 0;
cd4b0b20
TC
118 }
119 }
120#endif
74315ca9
TC
121 ctx->error_sp = IM_ERROR_COUNT-1;
122}
123
606237f9 124/*
d03fd5a4 125=item i_push_error(int code, char const *msg)
6cfee9d1
TC
126=synopsis i_push_error(0, "Yep, it's broken");
127=synopsis i_push_error(errno, "Error writing");
92bda632
TC
128=category Error handling
129
6cfee9d1 130Called by an Imager function to push an error message onto the stack.
606237f9
TC
131
132No message is pushed if the stack is full (since this means someone
133forgot to call i_clear_error(), or that a function that doesn't do
134error handling is calling function that does.).
135
136=cut
137*/
74315ca9
TC
138void
139im_push_error(im_context_t ctx, int code, char const *msg) {
8d14daab 140 size_t size = strlen(msg)+1;
606237f9 141
74315ca9 142 if (ctx->error_sp <= 0)
606237f9
TC
143 /* bad, bad programmer */
144 return;
145
74315ca9
TC
146 --ctx->error_sp;
147 if (ctx->error_alloc[ctx->error_sp] < size) {
148 if (ctx->error_stack[ctx->error_sp].msg)
149 myfree(ctx->error_stack[ctx->error_sp].msg);
f0960b14 150 /* memory allocated on the following line is only ever released when
606237f9 151 we need a bigger string */
f0960b14
TC
152 /* size is size (len+1) of an existing string, overflow would mean
153 the system is broken anyway */
74315ca9
TC
154 ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */
155 ctx->error_alloc[ctx->error_sp] = size;
606237f9 156 }
74315ca9
TC
157 strcpy(ctx->error_stack[ctx->error_sp].msg, msg);
158 ctx->error_stack[ctx->error_sp].code = code;
159}
d03fd5a4 160
c5cf7614 161/*
d03fd5a4
TC
162=item i_push_errorvf(int C<code>, char const *C<fmt>, va_list C<ap>)
163
92bda632
TC
164=category Error handling
165
c5cf7614
TC
166Intended for use by higher level functions, takes a varargs pointer
167and a format to produce the finally pushed error message.
168
6cfee9d1
TC
169Does not support perl specific format codes.
170
c5cf7614
TC
171=cut
172*/
74315ca9
TC
173void
174im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) {
c5cf7614 175 char buf[1024];
86c8d19a
TC
176#if defined(IMAGER_VSNPRINTF)
177 vsnprintf(buf, sizeof(buf), fmt, ap);
178#elif defined(_MSC_VER)
c5cf7614
TC
179 _vsnprintf(buf, sizeof(buf), fmt, ap);
180#else
181 /* is there a way to detect vsnprintf()?
182 for this and other functions we need some mechanism to handle
183 detection (like perl's Configure, or autoconf)
184 */
185 vsprintf(buf, fmt, ap);
186#endif
74315ca9
TC
187 im_push_error(ctx, code, buf);
188}
189
190void
44d86483 191(i_push_errorvf)(int code, char const *fmt, va_list ap) {
74315ca9 192 im_push_errorvf(im_get_context(), code, fmt, ap);
9c852bc4
TC
193}
194
c5cf7614
TC
195/*
196=item i_push_errorf(int code, char const *fmt, ...)
6cfee9d1 197=synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno);
92bda632
TC
198=category Error handling
199
5715f7c3 200A version of i_push_error() that does printf() like formatting.
c5cf7614 201
6cfee9d1
TC
202Does not support perl specific format codes.
203
c5cf7614
TC
204=cut
205*/
74315ca9
TC
206void
207i_push_errorf(int code, char const *fmt, ...) {
c5cf7614
TC
208 va_list ap;
209 va_start(ap, fmt);
210 i_push_errorvf(code, fmt, ap);
211 va_end(ap);
606237f9
TC
212}
213
74315ca9
TC
214void
215im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) {
216 va_list ap;
217 va_start(ap, fmt);
218 im_push_errorvf(ctx, code, fmt, ap);
219 va_end(ap);
220}
221
f0960b14
TC
222#ifdef IMAGER_I_FAILED
223#error "This isn't used and is untested"
224
606237f9
TC
225/*
226=item i_failed(char const *msg)
227
228Called by Imager code to indicate that a top-level has failed.
229
c5cf7614 230msg can be NULL, in which case no error is pushed.
606237f9
TC
231
232Calls the current failed callback, if any.
233
234Aborts the program with an error, if failures have been set to be fatal.
235
236Returns zero if it does not abort.
237
238=cut
239*/
c5cf7614 240int i_failed(int code, char const *msg) {
606237f9 241 if (msg)
c5cf7614 242 i_push_error(code, msg);
606237f9
TC
243 if (failed_cb)
244 failed_cb(error_stack + error_sp);
245 if (failures_fatal) {
c5cf7614 246 int sp;
8d14daab 247 size_t total; /* total length of error messages */
c5cf7614 248 char *full; /* full message for logging */
606237f9
TC
249 if (argv0)
250 fprintf(stderr, "%s: ", argv0);
251 fputs("error:\n", stderr);
c5cf7614
TC
252 sp = error_sp;
253 while (error_stack[sp].msg) {
a743c0a6 254 fprintf(stderr, " %s\n", error_stack[sp].msg);
c5cf7614
TC
255 ++sp;
256 }
257 /* we want to log the error too, build an error message to hand to
b1e96952 258 i_fatal() */
c5cf7614
TC
259 total = 1; /* remember the NUL */
260 for (sp = error_sp; error_stack[sp].msg; ++sp) {
8d14daab
TC
261 size_t new_total += strlen(error_stack[sp].msg) + 2;
262 if (new_total < total) {
263 /* overflow, somehow */
264 break;
265 }
c5cf7614 266 }
a6c47345 267 full = mymalloc(total);
c5cf7614
TC
268 if (!full) {
269 /* just quit, at least it's on stderr */
270 exit(EXIT_FAILURE);
271 }
272 *full = 0;
273 for (sp = error_sp; error_stack[sp].msg; ++sp) {
274 strcat(full, error_stack[sp].msg);
275 strcat(full, ": ");
606237f9 276 }
c5cf7614
TC
277 /* lose the extra ": " */
278 full[strlen(full)-2] = '\0';
b1e96952 279 i_fatal(EXIT_FAILURE, "%s", full);
606237f9
TC
280 }
281
282 return 0;
283}
284
f0960b14
TC
285#endif
286
b3afeed5
TC
287/*
288=item im_assert_fail(file, line, message)
289
290Called when an im_assert() assertion fails.
291
292=cut
293*/
294
295void
296im_assert_fail(char const *file, int line, char const *message) {
297 fprintf(stderr, "Assertion failed line %d file %s: %s\n",
298 line, file, message);
74315ca9 299 abort();
b3afeed5
TC
300}
301
606237f9
TC
302/*
303=back
304
305=head1 BUGS
306
307This interface isn't thread safe.
308
309=head1 AUTHOR
310
311Tony Cook <tony@develop-help.com>
312
313Stack concept by Arnar Mar Hrafnkelsson <addi@umich.edu>
314
315=cut
316*/