ext/RMagick/rmutil.c in rmagick-1.10.1 vs ext/RMagick/rmutil.c in rmagick-1.11.0
- old
+ new
@@ -1,22 +1,23 @@
-/* $Id: rmutil.c,v 1.66 2006/01/20 23:59:46 rmagick Exp $ */
+/* $Id: rmutil.c,v 1.75 2006/05/07 23:40:14 rmagick Exp $ */
/*============================================================================\
| Copyright (C) 2006 by Timothy P. Hunter
| Name: rmutil.c
| Author: Tim Hunter
| Purpose: Utility functions for RMagick
\============================================================================*/
#include "rmagick.h"
#include <errno.h>
-static const char *Compliance_name(ComplianceType *);
+static const char *ComplianceType_name(ComplianceType *);
static const char *StyleType_name(StyleType);
static const char *StretchType_name(StretchType);
static void Color_Name_to_PixelPacket(PixelPacket *, VALUE);
static VALUE Enum_type_values(VALUE);
static VALUE Enum_type_inspect(VALUE);
+static void handle_exception(ExceptionInfo *, Image *, ErrorRetention);
/*
Extern: magick_malloc, magick_free, magick_realloc
Purpose: ****Magick versions of standard memory routines.
Notes: use when managing memory that ****Magick may have
@@ -275,10 +276,75 @@
return pct;
}
/*
+ Static: check_num2dbl
+ Purpose: return 0 if rb_num2dbl doesn't raise an exception
+ */
+static VALUE
+check_num2dbl(VALUE obj)
+{
+ rb_num2dbl(obj);
+ return INT2FIX(1);
+}
+
+
+/*
+ Static: rescue_not_dbl
+ Purpose: called if rb_num2dbl raises an exception
+ */
+static VALUE
+rescue_not_dbl(VALUE ignored)
+{
+ return INT2FIX(0);
+}
+
+
+/*
+ Extern: rm_check_num2dbl
+ Purpose: Return 1 if the object can be converted to a double, 0 otherwise.
+*/
+int rm_check_num2dbl(VALUE obj)
+{
+ return FIX2INT(rb_rescue(check_num2dbl, obj, rescue_not_dbl, (VALUE)0));
+}
+
+
+/*
+ * Extern: rm_str_to_pct
+ * Purpose: Given a string in the form NN% return the corresponding double.
+ *
+*/
+double rm_str_to_pct(VALUE str)
+{
+ long pct;
+ char *pct_str, *end;
+
+ str = rb_rescue(rb_str_to_str, str, rescue_not_str, str);
+ pct_str = STRING_PTR(str);
+ errno = 0;
+ pct = strtol(pct_str, &end, 10);
+
+ if (errno == ERANGE)
+ {
+ rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
+ }
+ if (*end != '%')
+ {
+ rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
+ }
+ if (pct < 0L)
+ {
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
+ }
+
+ return pct / 100.0;
+}
+
+
+/*
* Extern: rm_fuzz_to_dbl(obj)
* Purpose: If the argument is a number, convert it to a double.
* Otherwise it's supposed to be a string in the form 'NN%'.
* Return a percentage of MaxRGB.
* Notes: Called from Image#fuzz= and Info#fuzz=
@@ -415,11 +481,11 @@
class = class; // defeat "never referenced" message from icc
GetExceptionInfo(&exception);
okay = QueryColorDatabase(STRING_PTR(name), &pp, &exception);
- HANDLE_ERROR
+ CHECK_EXCEPTION()
if (!okay)
{
rb_raise(rb_eArgError, "invalid color name: %s", STRING_PTR(name));
}
@@ -484,11 +550,11 @@
image->matte = matte;
DestroyImageInfo(info);
GetExceptionInfo(&exception);
(void) QueryColorname(image, pixel, compliance, name, &exception);
DestroyImage(image);
- HANDLE_ERROR
+ CHECK_EXCEPTION()
// Always return a string, even if it's ""
return rb_str_new2(name);
}
@@ -910,11 +976,11 @@
ExceptionInfo exception;
GetExceptionInfo(&exception);
(void) QueryColorname(image, color, X11Compliance, name, &exception);
- HANDLE_ERROR_IMG(image)
+ CHECK_EXCEPTION()
return rb_str_new2(name);
}
/*
@@ -1150,11 +1216,11 @@
{
const char *name;
// Turn off undefined bits
compliance &= (SVGCompliance|X11Compliance|XPMCompliance);
- name = Compliance_name(&compliance);
+ name = ComplianceType_name(&compliance);
return rm_enum_new(Class_ComplianceType, ID2SYM(rb_intern(name)), INT2FIX(compliance));
}
/*
@@ -1288,11 +1354,11 @@
/*
Static: DisposeType_name
Purpose: Return the name of a DisposeType enum as a string
*/
static const char *
-DisposeType_name(type)
+DisposeType_name(DisposeType type)
{
switch(type)
{
default:
ENUM_TO_NAME(UndefinedDispose)
@@ -1365,11 +1431,11 @@
/*
Static: EndianType_name
Purpose: Return the name of a EndianType enum as a string
*/
static const char *
-EndianType_name(type)
+EndianType_name(EndianType type)
{
switch(type)
{
default:
ENUM_TO_NAME(UndefinedEndian)
@@ -1396,11 +1462,11 @@
/*
Static: ImageType_name
Purpose: Return the name of a ImageType enum as a string
*/
static char *
-ImageType_name(type)
+ImageType_name(ImageType type)
{ switch(type)
{
default:
ENUM_TO_NAME(UndefinedType)
ENUM_TO_NAME(BilevelType)
@@ -1435,11 +1501,11 @@
/*
Static: InterlaceType_name
Purpose: Return the name of a InterlaceType enum as a string
*/
static const char *
-InterlaceType_name(interlace)
+InterlaceType_name(InterlaceType interlace)
{
switch(interlace)
{
default:
ENUM_TO_NAME(UndefinedInterlace)
@@ -1463,17 +1529,51 @@
name = InterlaceType_name(interlace);
return rm_enum_new(Class_InterlaceType, ID2SYM(rb_intern(name)), INT2FIX(interlace));
}
+/*
+ External: MagickLayerMethod_new
+ Purpose: Construct an MagickLayerMethod enum object for the specified value.
+*/
+#if defined(HAVE_COMPAREIMAGELAYERS)
+static const char *
+MagickLayerMethod_name(MagickLayerMethod method)
+{
+ switch(method)
+ {
+ default:
+ ENUM_TO_NAME(UndefinedLayer)
+ ENUM_TO_NAME(CompareAnyLayer)
+ ENUM_TO_NAME(CompareClearLayer)
+ ENUM_TO_NAME(CompareOverlayLayer)
+ ENUM_TO_NAME(OptimizeLayer)
+ ENUM_TO_NAME(OptimizePlusLayer)
+#if defined(HAVE_COALESCELAYER)
+ ENUM_TO_NAME(CoalesceLayer)
+ ENUM_TO_NAME(DisposeLayer)
+#endif
+ }
+}
+VALUE
+MagickLayerMethod_new(MagickLayerMethod method)
+{
+ const char *name;
+
+ name = MagickLayerMethod_name(method);
+ return rm_enum_new(Class_MagickLayerMethod, ID2SYM(rb_intern(name)), INT2FIX(method));
+}
+#endif
+
+
/*
Static: RenderingIntent_name
Purpose: Return the name of a RenderingIntent enum as a string
*/
static const char *
-RenderingIntent_name(intent)
+RenderingIntent_name(RenderingIntent intent)
{
switch(intent)
{
default:
ENUM_TO_NAME(UndefinedIntent)
@@ -1504,11 +1604,11 @@
/*
Static: ResolutionType_name
Purpose: Return the name of a ResolutionType enum as a string
*/
static const char *
-ResolutionType_name(type)
+ResolutionType_name(ResolutionType type)
{
switch(type)
{
default:
ENUM_TO_NAME(UndefinedResolution)
@@ -1538,11 +1638,11 @@
/*
Static: OrientationType_name
Purpose: Return the name of a OrientationType enum as a string
*/
static const char *
-OrientationType_name(type)
+OrientationType_name(OrientationType type)
{
switch(type)
{
default:
ENUM_TO_NAME(UndefinedOrientation)
@@ -1657,11 +1757,11 @@
Color_to_ColorInfo(&ci, self);
sprintf(buff, "name=%s, compliance=%s, "
"color.red=%d, color.green=%d, color.blue=%d, color.opacity=%d ",
ci.name,
- Compliance_name(&ci.compliance),
+ ComplianceType_name(&ci.compliance),
ci.color.red, ci.color.green, ci.color.blue, ci.color.opacity);
destroy_ColorInfo(&ci);
return rb_str_new2(buff);
}
@@ -1991,18 +2091,18 @@
volatile VALUE name, description, family;
volatile VALUE style, stretch, weight;
volatile VALUE encoding, foundry, format;
name = rb_str_new2(ti->name);
- description = rb_str_new2(ti->description);
family = rb_str_new2(ti->family);
style = StyleType_new(ti->style);
stretch = StretchType_new(ti->stretch);
weight = INT2NUM(ti->weight);
- encoding = ti->encoding ? rb_str_new2(ti->encoding) : Qnil;
- foundry = ti->foundry ? rb_str_new2(ti->foundry) : Qnil;
- format = ti->format ? rb_str_new2(ti->format) : Qnil;
+ description = ti->description ? rb_str_new2(ti->description) : Qnil;
+ encoding = ti->encoding ? rb_str_new2(ti->encoding) : Qnil;
+ foundry = ti->foundry ? rb_str_new2(ti->foundry) : Qnil;
+ format = ti->format ? rb_str_new2(ti->format) : Qnil;
return rb_funcall(Class_Font, ID_new, 9
, name, description, family, style
, stretch, weight, encoding, foundry, format);
}
@@ -2286,12 +2386,15 @@
Purpose: Enum class alloc function
*/
VALUE Enum_alloc(VALUE class)
{
MagickEnum *magick_enum;
+ volatile VALUE enumr;
- return Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
+ enumr = Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
+ OBJ_FREEZE(enumr);
+ return enumr;
}
#else
/*
@@ -2309,18 +2412,19 @@
Notes: `class' can be an Enum subclass
*/
VALUE Enum_new(VALUE class, VALUE sym, VALUE val)
{
volatile VALUE new_enum;
- VALUE argv[2];
+ volatile VALUE argv[2];
MagickEnum *magick_enum;
new_enum = Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
argv[0] = sym;
argv[1] = val;
rb_obj_call_init(new_enum, 2, argv);
+ OBJ_FREEZE(new_enum);
return new_enum;
}
#endif
@@ -2456,39 +2560,54 @@
return rb_str_new2(str);
}
/*
- * Method: xxx.each
- * Purpose: singleton iterator over enumerators list
+ * Method: xxx.values
+ * Purpose: Behaves like #each if a block is present, otherwise like #to_a.
* Notes: defined for each Enum subclass
*/
static VALUE Enum_type_values(VALUE class)
{
- volatile VALUE enumerators;
+ volatile VALUE enumerators, copy;
+ volatile VALUE rv;
int x;
enumerators = rb_cvar_get(class, ID_enumerators);
- for (x = 0; x < RARRAY(enumerators)->len; x++)
+ if (rb_block_given_p())
{
- rb_yield(rb_ary_entry(enumerators, x));
+ for (x = 0; x < RARRAY(enumerators)->len; x++)
+ {
+ rb_yield(rb_ary_entry(enumerators, x));
+ }
+ rv = class;
}
+ else
+ {
+ copy = rb_ary_new2(RARRAY(enumerators)->len);
+ for (x = 0; x < RARRAY(enumerators)->len; x++)
+ {
+ rb_ary_push(copy, rb_ary_entry(enumerators, x));
+ }
+ OBJ_FREEZE(copy);
+ rv = copy;
+ }
- return class;
+ return rv;
}
/*
- Static: Compliance_name
+ Static: ComplianceType_name
Purpose: Return the string representation of a ComplianceType value
Notes: xMagick will OR multiple compliance types so we have to
arbitrarily pick one name. Set the compliance argument
to the selected value.
*/
static const char *
-Compliance_name(ComplianceType *c)
+ComplianceType_name(ComplianceType *c)
{
if ((*c & (SVGCompliance|X11Compliance|XPMCompliance))
== (SVGCompliance|X11Compliance|XPMCompliance))
{
return "AllCompliance";
@@ -2660,11 +2779,11 @@
registry_id = SetMagickRegistry(ImageRegistryType, image, sizeof(Image), &image->exception);
if (registry_id < 0)
{
rb_raise(rb_eRuntimeError, "SetMagickRegistry failed.");
}
- HANDLE_ERROR_IMG(image)
+ rm_check_image_exception(image, RetainOnError);
sprintf(tmpnam, "mpri:%ld", registry_id);
}
/*
@@ -2804,231 +2923,381 @@
}
/*
- Static: magick_error_handler
- Purpose: Build error or warning message string. If the error
- is severe, raise the ImageMagickError exception,
- otherwise print an optional warning.
-*/
-static void
-magick_error_handler(
- ExceptionType severity,
- const char *reason,
- const char *description
-#if defined(HAVE_EXCEPTIONINFO_MODULE)
- ,
- const char *module,
- const char *function,
- unsigned long line
-#endif
- )
+ * Extern: rm_clone_image
+ * Purpose: clone an image, handle errors
+ */
+Image *rm_clone_image(Image *image)
{
- char msg[1024];
+ Image *clone;
+ ExceptionInfo exception;
- if (severity >= ErrorException)
+ GetExceptionInfo(&exception);
+ clone = CloneImage(image, 0, 0, True, &exception);
+ if (!clone)
{
-#if defined(HAVE_SNPRINTF)
- snprintf(msg, sizeof(msg)-1,
-#else
- sprintf(msg,
-#endif
- "%s%s%s",
- GetLocaleExceptionMessage(severity, reason),
- description ? ": " : "",
- description ? GetLocaleExceptionMessage(severity, description) : "");
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
+ }
+ rm_check_exception(&exception, clone, DestroyOnError);
-#if defined(HAVE_EXCEPTIONINFO_MODULE)
- {
- char extra[100];
+ return clone;
+}
-#if defined(HAVE_SNPRINTF)
- snprintf(extra, sizeof(extra)-1, "%s at %s:%lu", function, module, line);
+
+/*
+ Extern: rm_progress_monitor
+ Purpose: SetImage(Info)ProgressMonitor exit
+ Notes: ImageMagick's "tag" argument is unused. We pass along the method name instead.
+*/
+#if defined(HAVE_SETIMAGEPROGRESSMONITOR)
+MagickBooleanType rm_progress_monitor(
+ const char *tag,
+ const MagickOffsetType of,
+ const MagickSizeType sp,
+ void *client_data)
+{
+ volatile VALUE rval;
+ volatile VALUE method, offset, span;
+
+#if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
+ offset = rb_ll2inum(of);
+ span = rb_ull2inum(sp);
#else
- sprintf(extra, "%s at %s:%lu", function, module, line);
+ offset = rb_int2big((long)of);
+ span = rb_uint2big((unsigned long)sp);
#endif
- raise_error(msg, extra);
- }
-#else
- raise_error(msg, NULL);
-#endif
- }
- else if (severity != UndefinedException)
- {
-#if defined(HAVE_SNPRINTF)
- snprintf(msg, sizeof(msg)-1,
-#else
- sprintf(msg,
-#endif
- "RMagick: %s%s%s",
- GetLocaleExceptionMessage(severity, reason),
- description ? ": " : "",
- description ? GetLocaleExceptionMessage(severity, description) : "");
- rb_warning(msg);
- }
+
+ method = rb_str_new2(rb_id2name(rb_frame_last_func()));
+
+ rval = rb_funcall((VALUE)client_data, ID_call, 3, method, offset, span);
+
+ return RTEST(rval) ? MagickTrue : MagickFalse;
}
+#endif
/*
- Extern: handle_error
- Purpose: Called from RMagick routines to issue warning messages
- and raise the ImageMagickError exception.
- Notes: In order to free up memory before calling raise, this
- routine copies the ExceptionInfo data to local storage
- and then calls DestroyExceptionInfo before raising
- the error.
-
- If the exception is an error, DOES NOT RETURN!
+ Extern: rm_split
+ Purpose: Remove the ImageMagick links between images in an scene
+ sequence.
+ Notes: The images remain grouped via the ImageList
*/
void
-rm_handle_error(ExceptionInfo *ex)
+rm_split(Image *image)
{
-#define RM_MAX_ERROR_CLAUSE 250
- ExceptionType sev = ex->severity;
- char reason[RM_MAX_ERROR_CLAUSE+1];
- char desc[RM_MAX_ERROR_CLAUSE+1];
-#if defined(HAVE_EXCEPTIONINFO_MODULE)
- char module[RM_MAX_ERROR_CLAUSE+1], function[RM_MAX_ERROR_CLAUSE+1];
- unsigned long line;
-#endif
-
- reason[0] = '\0';
- desc[0] = '\0';
-
- if (sev == UndefinedException)
+ if (!image)
{
- return;
+ rb_bug("RMagick FATAL: unseq called with NULL argument.");
}
- if (ex->reason)
+ while (image)
{
- strncpy(reason, ex->reason, RM_MAX_ERROR_CLAUSE);
- reason[RM_MAX_ERROR_CLAUSE] = '\0';
+ (void) RemoveFirstImageFromList(&image);
}
- if (ex->description)
+}
+
+
+
+/*
+ * Static: copy_exception
+ * clear_exception
+ * Purpose: Define alternative implementations of ImageMagick's
+ * InheritException and ClearMagickException.
+ * Notes: InheritException is ALWAYS defined in ImageMagick and
+ * NEVER defined in GraphicsMagick. ClearMagickException
+ * is defined in ImageMagick 6.2.6 and later and NEVER
+ * defined in GraphicsMagick.
+ *
+ * The purpose of InheritException is to copy the exception
+ * information from a "related" exception to a destination
+ * exception if the related exception is more severe than the
+ * destination exception.
+ *
+ * The purpose of ClearException is to reset the ExceptionInfo
+ * structure to its initial format.
+ */
+
+#if defined(HAVE_INHERITEXCEPTION)
+
+ // This is ImageMagick - InheritException is always defined
+ static void copy_exception(ExceptionInfo *exception, ExceptionInfo *relative)
{
- strncpy(desc, ex->description, RM_MAX_ERROR_CLAUSE);
- desc[RM_MAX_ERROR_CLAUSE] = '\0';
+ InheritException(exception, relative);
}
-#if defined(HAVE_EXCEPTIONINFO_MODULE)
- module[0] = '\0';
- function[0] = '\0';
+ // ImageMagick < 6.2.6 had a different kind of ExceptionInfo struct
+ // and doesn't define ClearMagickException.
+ #if defined(HAVE_CLEARMAGICKEXCEPTION)
+ static void clear_exception(ExceptionInfo *exception)
+ {
+ ClearMagickException(exception);
+ }
+ #else
- if (ex->module)
+ static void clear_exception(ExceptionInfo *exception)
+ {
+ DestroyExceptionInfo(exception);
+ GetExceptionInfo(exception);
+ }
+
+ #endif
+
+
+#else // !defined(HAVE_INHERITEXCEPTION)
+
+ // This is GraphicsMagick. Very old versions don't support the
+ // module, function, and line fields in the ExceptionInfo struct.
+
+ static void copy_exception(ExceptionInfo *exception, ExceptionInfo *relative)
{
- strncpy(module, ex->module, RM_MAX_ERROR_CLAUSE);
- module[RM_MAX_ERROR_CLAUSE] = '\0';
+ assert(exception != NULL);
+ assert(exception->signature == MagickSignature);
+ assert(relative != NULL);
+
+ if (relative->severity < exception->severity)
+ {
+ return;
+ }
+
+ DestroyExceptionInfo(exception);
+ GetExceptionInfo(exception);
+
+ exception->severity = relative->severity;
+ if (relative->reason)
+ {
+ magick_clone_string(&exception->reason, relative->reason);
+ }
+
+ if (relative->description)
+ {
+ magick_clone_string(&exception->description, relative->description);
+ }
+
+
+ #if defined(HAVE_EXCEPTIONINFO_MODULE)
+ if (relative->module)
+ {
+ magick_clone_string(&exception->module, relative->module);
+ }
+ if (relative->function)
+ {
+ magick_clone_string(&exception->function, relative->function);
+ }
+
+ exception->line = relative->line;
+ #endif
}
- if (ex->function)
+
+
+ static void clear_exception(ExceptionInfo *exception)
{
- strncpy(function, ex->function, RM_MAX_ERROR_CLAUSE);
- function[RM_MAX_ERROR_CLAUSE] = '\0';
+ DestroyExceptionInfo(exception);
+ GetExceptionInfo(exception);
}
- line = ex->line;
-#endif
- // Let ImageMagick reclaim its storage
- DestroyExceptionInfo(ex);
- // Reset the severity. If the exception structure is in an
- // Image and this exception is rescued and the Image reused,
- // we need the Image to be pristine!
- GetExceptionInfo(ex);
-
-#if !defined(HAVE_EXCEPTIONINFO_MODULE)
- magick_error_handler(sev, reason, desc);
-#else
- magick_error_handler(sev, reason, desc, module, function, line);
#endif
-}
+
/*
- Extern: handle_all_errors
- Purpose: Examine all the images in a sequence. If any
- image has an error, raise an exception. Otherwise
- if any image has a warning, issue a warning message.
-*/
-void rm_handle_all_errors(Image *seq)
+ Extern: rm_check_image_exception
+ Purpose: If an ExceptionInfo struct in a list of images indicates a warning,
+ issue a warning message. If an ExceptionInfo struct indicates an
+ error, raise an exception and optionally destroy the images.
+ */
+void
+rm_check_image_exception(Image *imglist, ErrorRetention retention)
{
+ ExceptionInfo exception;
Image *badboy = NULL;
- Image *image = seq;
+ Image *image;
+ if (imglist == NULL)
+ {
+ return;
+ }
+
+ GetExceptionInfo(&exception);
+
+ // Find the image with the highest severity
+ image = GetFirstImageInList(imglist);
while (image)
{
if (image->exception.severity != UndefinedException)
{
- // Stop at the 1st image with an error
- if (image->exception.severity > WarningException)
+ if (!badboy || image->exception.severity > badboy->exception.severity)
{
badboy = image;
- break;
+ copy_exception(&exception, &badboy->exception);
}
- else if (!badboy)
- {
- badboy = image;
- }
+
+ clear_exception(&image->exception);
}
image = GetNextImageInList(image);
}
if (badboy)
{
- if (badboy->exception.severity > WarningException)
- {
- rm_split(seq);
- }
- rm_handle_error(&badboy->exception);
+ rm_check_exception(&exception, imglist, retention);
}
}
+
/*
- Extern: rm_progress_monitor
- Purpose: SetImage(Info)ProgressMonitor exit
- Notes: ImageMagick's "tag" argument is unused. We pass along the method name instead.
+ * Extern: rm_check_exception
+ * Purpose: Call handle_exception if there is an exception to handle.
+ */
+void
+rm_check_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
+{
+ if (exception->severity == UndefinedException)
+ {
+ return;
+ }
+
+ handle_exception(exception, imglist, retention);
+}
+
+
+/*
+ * Static: handle_exception
+ * Purpose: called when rm_check_exception determines that we need
+ * to either issue a warning message or raise an exception.
+ * This function allocates a bunch of stack so we don't call
+ * it unless we have to.
*/
-#if defined(HAVE_SETIMAGEPROGRESSMONITOR)
-MagickBooleanType rm_progress_monitor(
- const char *tag,
- const MagickOffsetType of,
- const MagickSizeType sp,
- void *client_data)
+static void
+handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
{
- volatile VALUE rval;
- volatile VALUE method, offset, span;
-#if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
- offset = rb_ll2inum(of);
- span = rb_ull2inum(sp);
+ char reason[500];
+ char desc[500];
+ char msg[sizeof(reason)+sizeof(desc)+20];
+
+#if defined(HAVE_EXCEPTIONINFO_MODULE)
+ char module[200], function[200];
+ char extra[sizeof(module)+sizeof(function)+20];
+ unsigned long line;
+#endif
+
+
+ memset(msg, 0, sizeof(msg));
+
+
+ // Handle simple warning
+ if (exception->severity < ErrorException)
+ {
+#if defined(HAVE_SNPRINTF)
+ snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
#else
- offset = rb_int2big((long)of);
- span = rb_uint2big((unsigned long)sp);
+ sprintf(msg, "RMagick: %.500s%s%.500s",
#endif
+ GetLocaleExceptionMessage(exception->severity, exception->reason),
+ exception->description ? ": " : "",
+ exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
+ msg[sizeof(msg)-1] = '\0';
+ rb_warning(msg);
- method = rb_str_new2(rb_id2name(rb_frame_last_func()));
+ DestroyExceptionInfo(exception);
+ return;
+ }
- rval = rb_funcall((VALUE)client_data, ID_call, 3, method, offset, span);
+ // Raise an exception. We're not coming back...
- return RTEST(rval) ? MagickTrue : MagickFalse;
-}
+
+ // Newly-created images should be destroyed, images that are part
+ // of image objects should be retained but split.
+ if (imglist)
+ {
+ if (retention == DestroyOnError)
+ {
+ (void) DestroyImageList(imglist);
+ imglist = NULL;
+ }
+ else
+ {
+ rm_split(imglist);
+ }
+ }
+
+
+ // Clone the ExceptionInfo with all arguments on the stack.
+ memset(reason, 0, sizeof(reason));
+ memset(desc, 0, sizeof(desc));
+
+ if (exception->reason)
+ {
+ strncpy(reason, exception->reason, sizeof(reason)-1);
+ reason[sizeof(reason)-1] = '\0';
+ }
+ if (exception->description)
+ {
+ strncpy(desc, exception->description, sizeof(desc)-1);
+ desc[sizeof(desc)-1] = '\0';
+ }
+
+
+#if defined(HAVE_SNPRINTF)
+ snprintf(msg, sizeof(msg)-1, "%s%s%s",
+ GetLocaleExceptionMessage(exception->severity, reason),
+ desc[0] ? ": " : "",
+ desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
+#else
+ sprintf(msg, "%.*s%s%.*s",
+ sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
+ desc[0] ? ": " : "",
+ sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
#endif
+ msg[sizeof(msg)-1] = '\0';
-/*
- Extern: rm_split
- Purpose: Remove the ImageMagick links between images in an scene
- sequence.
- Notes: The images remain grouped via the ImageList
-*/
-void
-rm_split(Image *image)
-{
- if (!image)
+#if defined(HAVE_EXCEPTIONINFO_MODULE)
+
+ memset(module, 0, sizeof(module));
+ memset(function, 0, sizeof(function));
+ memset(extra, 0, sizeof(extra));
+
+ if (exception->module)
{
- rb_bug("RMagick FATAL: unseq called with NULL argument.");
+ strncpy(module, exception->module, sizeof(module)-1);
+ module[sizeof(module)-1] = '\0';
}
- while (image)
+ if (exception->function)
{
- (void) RemoveFirstImageFromList(&image);
+ strncpy(function, exception->function, sizeof(function)-1);
+ function[sizeof(function)-1] = '\0';
}
+ line = exception->line;
+
+#if defined(HAVE_SNPRINTF)
+ snprintf(extra, sizeof(extra)-1, "%s at %s:%lu", function, module, line);
+#else
+ sprintf(extra, "%.*s at %.*s:%lu", sizeof(function), function, sizeof(module), module, line);
+#endif
+
+ extra[sizeof(extra)-1] = '\0';
+
+ DestroyExceptionInfo(exception);
+ raise_error(msg, extra);
+
+#else
+ DestroyExceptionInfo(exception);
+ raise_error(msg, NULL);
+#endif
+
}
+
+
+/*
+ * Extern: rm_ensure_result
+ * Purpose: RMagick expected a result. If it got NULL instead raise an exception.
+ */
+void rm_ensure_result(Image *image)
+{
+ if (!image)
+ {
+ rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result.");
+ }
+}
+