X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/a6c47345e86b541cf380919eedd22c0747b93b4f..b96f5e9e574301854c7f78f3f55a40f3cc5e85e9:/error.c diff --git a/error.c b/error.c index dd6b94f3..03f5bef8 100644 --- a/error.c +++ b/error.c @@ -61,25 +61,15 @@ C). The Perl level won't use all of this. =cut */ -#include "image.h" +#include "imageri.h" #include #include -/* we never actually use the last item - it's the NULL terminator */ -#define ERRSTK 20 -i_errmsg error_stack[ERRSTK]; -int error_sp = ERRSTK - 1; -/* we track the amount of space used each string, so we don't reallocate - space unless we need to. - This also means that a memory tracking library may see the memory - allocated for this as a leak. */ -int error_space[ERRSTK]; - +#if 0 static i_error_cb error_cb; static i_failed_cb failed_cb; static int failures_fatal; static char *argv0; - /* =item i_set_argv0(char const *program) @@ -95,7 +85,9 @@ void i_set_argv0(char const *name) { char *dupl; if (!name) return; - dupl = mymalloc(strlen(name)+1); + /* if the user has an existing string of MAXINT length then + the system is broken anyway */ + dupl = mymalloc(strlen(name)+1); /* check 17jul05 tonyc */ strcpy(dupl, name); if (argv0) myfree(argv0); @@ -155,16 +147,22 @@ i_failed_cb i_set_failed_cb(i_failed_cb cb) { return old; } +#endif + /* -=item i_errors() +=item im_errors(ctx) +=synopsis i_errmsg *errors = im_errors(aIMCTX); +=synopsis i_errmsg *errors = i_errors(); Returns a pointer to the first element of an array of error messages, terminated by a NULL pointer. The highest level message is first. +Also callable as C. + =cut */ -i_errmsg *i_errors() { - return error_stack + error_sp; +i_errmsg *im_errors(im_context_t ctx) { + return ctx->error_stack + ctx->error_sp; } /* @@ -181,18 +179,39 @@ the mark. =over =item i_clear_error() +=synopsis i_clear_error(); +=category Error handling + +Clears the error stack. + +Called by any Imager function before doing any other processing. + +=cut +*/ -Called by any imager function before doing any other processing. +void +im_clear_error(im_context_t ctx) { +#ifdef IMAGER_DEBUG_MALLOC + int i; -=cut */ -void i_clear_error() { - error_sp = ERRSTK-1; + for (i = 0; i < IM_ERROR_COUNT; ++i) { + if (ctx->error_space[i]) { + myfree(ctx->error_stack[i].msg); + ctx->error_stack[i].msg = NULL; + ctx->error_space[i] = 0; + } + } +#endif + ctx->error_sp = IM_ERROR_COUNT-1; } /* =item i_push_error(int code, char const *msg) +=synopsis i_push_error(0, "Yep, it's broken"); +=synopsis i_push_error(errno, "Error writing"); +=category Error handling -Called by an imager function to push an error message onto the stack. +Called by an Imager function to push an error message onto the stack. No message is pushed if the stack is full (since this means someone forgot to call i_clear_error(), or that a function that doesn't do @@ -200,40 +219,56 @@ error handling is calling function that does.). =cut */ -void i_push_error(int code, char const *msg) { - int size = strlen(msg)+1; +void +im_push_error(im_context_t ctx, int code, char const *msg) { + size_t size = strlen(msg)+1; - if (error_sp <= 0) + if (ctx->error_sp <= 0) /* bad, bad programmer */ return; - --error_sp; - if (error_space[error_sp] < size) { - if (error_stack[error_sp].msg) - myfree(error_stack[error_sp].msg); - /* memory allocated on the following line is only ever release when + --ctx->error_sp; + if (ctx->error_alloc[ctx->error_sp] < size) { + if (ctx->error_stack[ctx->error_sp].msg) + myfree(ctx->error_stack[ctx->error_sp].msg); + /* memory allocated on the following line is only ever released when we need a bigger string */ - error_stack[error_sp].msg = mymalloc(size); - error_space[error_sp] = size; + /* size is size (len+1) of an existing string, overflow would mean + the system is broken anyway */ + ctx->error_stack[ctx->error_sp].msg = mymalloc(size); /* checked 17jul05 tonyc */ + ctx->error_alloc[ctx->error_sp] = size; } - strcpy(error_stack[error_sp].msg, msg); - error_stack[error_sp].code = code; + strcpy(ctx->error_stack[ctx->error_sp].msg, msg); + ctx->error_stack[ctx->error_sp].code = code; +} + +#if 0 - if (error_cb) - error_cb(code, msg); +void +i_push_error(int code, char const *msg) { + im_push_error(im_get_context(), code, msg); } +#endif + /* -=item i_push_errorvf(int code, char const *fmt, va_list ap) +=item i_push_errorvf(int C, char const *C, va_list C) + +=category Error handling Intended for use by higher level functions, takes a varargs pointer and a format to produce the finally pushed error message. +Does not support perl specific format codes. + =cut */ -void i_push_errorvf(int code, char const *fmt, va_list ap) { +void +im_push_errorvf(im_context_t ctx, int code, char const *fmt, va_list ap) { char buf[1024]; -#if defined(_MSC_VER) +#if defined(IMAGER_VSNPRINTF) + vsnprintf(buf, sizeof(buf), fmt, ap); +#elif defined(_MSC_VER) _vsnprintf(buf, sizeof(buf), fmt, ap); #else /* is there a way to detect vsnprintf()? @@ -242,23 +277,44 @@ void i_push_errorvf(int code, char const *fmt, va_list ap) { */ vsprintf(buf, fmt, ap); #endif - i_push_error(code, buf); + im_push_error(ctx, code, buf); +} + +void +(i_push_errorvf)(int code, char const *fmt, va_list ap) { + im_push_errorvf(im_get_context(), code, fmt, ap); } /* =item i_push_errorf(int code, char const *fmt, ...) +=synopsis i_push_errorf(errno, "Cannot open file %s: %d", filename, errno); +=category Error handling + +A version of i_push_error() that does printf() like formatting. -A version of i_push_error() that does printf() like formating. +Does not support perl specific format codes. =cut */ -void i_push_errorf(int code, char const *fmt, ...) { +void +i_push_errorf(int code, char const *fmt, ...) { va_list ap; va_start(ap, fmt); i_push_errorvf(code, fmt, ap); va_end(ap); } +void +im_push_errorf(im_context_t ctx, int code, char const *fmt, ...) { + va_list ap; + va_start(ap, fmt); + im_push_errorvf(ctx, code, fmt, ap); + va_end(ap); +} + +#ifdef IMAGER_I_FAILED +#error "This isn't used and is untested" + /* =item i_failed(char const *msg) @@ -281,7 +337,7 @@ int i_failed(int code, char const *msg) { failed_cb(error_stack + error_sp); if (failures_fatal) { int sp; - int total; /* total length of error messages */ + size_t total; /* total length of error messages */ char *full; /* full message for logging */ if (argv0) fprintf(stderr, "%s: ", argv0); @@ -292,10 +348,14 @@ int i_failed(int code, char const *msg) { ++sp; } /* we want to log the error too, build an error message to hand to - m_fatal() */ + i_fatal() */ total = 1; /* remember the NUL */ for (sp = error_sp; error_stack[sp].msg; ++sp) { - total += strlen(error_stack[sp].msg) + 2; + size_t new_total += strlen(error_stack[sp].msg) + 2; + if (new_total < total) { + /* overflow, somehow */ + break; + } } full = mymalloc(total); if (!full) { @@ -309,12 +369,29 @@ int i_failed(int code, char const *msg) { } /* lose the extra ": " */ full[strlen(full)-2] = '\0'; - m_fatal(EXIT_FAILURE, "%s", full); + i_fatal(EXIT_FAILURE, "%s", full); } return 0; } +#endif + +/* +=item im_assert_fail(file, line, message) + +Called when an im_assert() assertion fails. + +=cut +*/ + +void +im_assert_fail(char const *file, int line, char const *message) { + fprintf(stderr, "Assertion failed line %d file %s: %s\n", + line, file, message); + abort(); +} + /* =back