cairo/util/cairo-script/cairo-script-objects.c
M Joonas Pihlaja 265ebd372a [script] Flesh out the relational comparison operators to be more PostScript-like.
The relational comparison operators can now compare strings vs names
by content as well as performing automatic type promotions on the
numeric types.  For other types relational comparisons succeeed
only if the values compare equal according to the eq operator, and
put the interpreter into a type-error state otherwise.
2008-12-12 12:00:42 +00:00

861 lines
21 KiB
C

/*
* Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-script-private.h"
#include <string.h>
csi_status_t
csi_array_new (csi_t *ctx,
csi_object_t *obj)
{
csi_array_t *array;
csi_status_t status;
array = _csi_slab_alloc (ctx, sizeof (csi_array_t));
if (_csi_unlikely (array == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
array->base.type = CSI_OBJECT_TYPE_ARRAY;
array->base.ref = 1;
status = _csi_stack_init (ctx, &array->stack, 32);
if (_csi_unlikely (status)) {
_csi_slab_free (ctx, array, sizeof (csi_array_t));
return status;
}
obj->type = CSI_OBJECT_TYPE_ARRAY;
obj->datum.array = array;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_array_put (csi_t *ctx,
csi_array_t *array,
csi_integer_t elem,
csi_object_t *value)
{
if (_csi_unlikely (elem < 0))
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
if (_csi_unlikely (elem >= array->stack.len)) {
csi_status_t status;
status = _csi_stack_grow (ctx, &array->stack, elem + 1);
if (_csi_unlikely (status))
return status;
memset (array->stack.objects + array->stack.len,
0, (elem - array->stack.len + 1) * sizeof (csi_object_t));
array->stack.len = elem + 1;
}
csi_object_free (ctx, &array->stack.objects[elem]);
array->stack.objects[elem] = *csi_object_reference (value);
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_array_get (csi_t *ctx,
csi_array_t *array,
csi_integer_t elem,
csi_object_t *value)
{
if (_csi_unlikely (elem < 0))
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
if (_csi_unlikely (elem > array->stack.len))
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
*value = array->stack.objects[elem];
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_array_append (csi_t *ctx,
csi_array_t *array,
csi_object_t *obj)
{
return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj));
}
inline csi_status_t
_csi_array_execute (csi_t *ctx, csi_array_t *array)
{
csi_integer_t i;
csi_status_t status;
if (_csi_unlikely (array->stack.len == 0))
return CSI_STATUS_SUCCESS;
for (i = 0; i < array->stack.len; i++) {
csi_object_t *obj = &array->stack.objects[i];
if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) {
if (obj->type == (CSI_OBJECT_TYPE_ARRAY |
CSI_OBJECT_ATTR_EXECUTABLE))
{
status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
}
else
status = csi_object_execute (ctx, &array->stack.objects[i]);
} else
status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
if (_csi_unlikely (status))
return status;
}
return CSI_STATUS_SUCCESS;
}
void
csi_array_free (csi_t *ctx, csi_array_t *array)
{
_csi_stack_fini (ctx, &array->stack);
_csi_slab_free (ctx, array, sizeof (csi_array_t));
}
csi_status_t
csi_boolean_new (csi_t *ctx,
csi_object_t *obj,
csi_boolean_t v)
{
obj->type = CSI_OBJECT_TYPE_BOOLEAN;
obj->datum.boolean = v;
return CSI_STATUS_SUCCESS;
}
static cairo_bool_t
_dictionary_name_equal (const void *_a, const void *_b)
{
const csi_dictionary_entry_t *a = _a;
const csi_dictionary_entry_t *b = _b;
return a->hash_entry.hash == b->hash_entry.hash;
}
csi_status_t
csi_dictionary_new (csi_t *ctx,
csi_object_t *obj)
{
csi_dictionary_t *dict;
csi_status_t status;
dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t));
if (_csi_unlikely (dict == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
dict->base.type = CSI_OBJECT_TYPE_DICTIONARY;
dict->base.ref = 1;
status = _csi_hash_table_init (&dict->hash_table, _dictionary_name_equal);
if (_csi_unlikely (status)) {
_csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
return status;
}
obj->type = CSI_OBJECT_TYPE_DICTIONARY;
obj->datum.dictionary = dict;
return CSI_STATUS_SUCCESS;
}
struct _dictionary_entry_pluck {
csi_t *ctx;
csi_hash_table_t *hash_table;
};
static void
_dictionary_entry_pluck (void *entry, void *data)
{
csi_dictionary_entry_t *dict_entry;
struct _dictionary_entry_pluck *pluck_data;
dict_entry = entry;
pluck_data = data;
_csi_hash_table_remove (pluck_data->hash_table, entry);
csi_object_free (pluck_data->ctx, &dict_entry->value);
_csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t));
}
void
csi_dictionary_free (csi_t *ctx,
csi_dictionary_t *dict)
{
struct _dictionary_entry_pluck data;
data.ctx = ctx;
data.hash_table = &dict->hash_table;
_csi_hash_table_foreach (&dict->hash_table,
_dictionary_entry_pluck,
&data);
_csi_hash_table_fini (&dict->hash_table);
_csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
}
csi_status_t
csi_dictionary_put (csi_t *ctx,
csi_dictionary_t *dict,
csi_name_t name,
csi_object_t *value)
{
csi_dictionary_entry_t *entry;
csi_status_t status;
entry = _csi_hash_table_lookup (&dict->hash_table,
(csi_hash_entry_t *) &name);
if (entry != NULL) {
/* replace the existing entry */
csi_object_free (ctx, &entry->value);
entry->value = *csi_object_reference (value);
return CSI_STATUS_SUCCESS;
}
entry = _csi_slab_alloc (ctx, sizeof (*entry));
if (_csi_unlikely (entry == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
entry->hash_entry.hash = name;
status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry);
if (_csi_unlikely (status)) {
_csi_slab_free (ctx, entry, sizeof (*entry));
return status;
}
entry->value = *csi_object_reference (value);
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_dictionary_get (csi_t *ctx,
csi_dictionary_t *dict,
csi_name_t name,
csi_object_t *value)
{
csi_dictionary_entry_t *entry;
entry = _csi_hash_table_lookup (&dict->hash_table,
(csi_hash_entry_t *) &name);
if (_csi_unlikely (entry == NULL))
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
*value = entry->value;
return CSI_STATUS_SUCCESS;
}
csi_boolean_t
csi_dictionary_has (csi_dictionary_t *dict,
csi_name_t name)
{
return _csi_hash_table_lookup (&dict->hash_table,
(csi_hash_entry_t *) &name) != NULL;
}
void
csi_dictionary_remove (csi_t *ctx,
csi_dictionary_t *dict,
csi_name_t name)
{
csi_dictionary_entry_t *entry;
entry = _csi_hash_table_lookup (&dict->hash_table,
(csi_hash_entry_t *) &name);
if (entry != NULL) {
_csi_hash_table_remove (&dict->hash_table, &entry->hash_entry);
csi_object_free (ctx, &entry->value);
_csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t));
}
}
csi_status_t
csi_integer_new (csi_t *ctx,
csi_object_t *obj,
csi_integer_t v)
{
obj->type = CSI_OBJECT_TYPE_INTEGER;
obj->datum.integer = v;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_matrix_new (csi_t *ctx,
csi_object_t *obj)
{
csi_matrix_t *matrix;
matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
if (_csi_unlikely (matrix == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
matrix->base.ref = 1;
cairo_matrix_init_identity (&matrix->matrix);
obj->type = CSI_OBJECT_TYPE_MATRIX;
obj->datum.matrix = matrix;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_matrix_new_from_array (csi_t *ctx,
csi_object_t *obj,
csi_array_t *array)
{
csi_matrix_t *matrix;
if (_csi_unlikely (array->stack.len != 6))
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
if (_csi_unlikely (matrix == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
matrix->base.ref = 1;
cairo_matrix_init (&matrix->matrix,
csi_number_get_value (&array->stack.objects[0]),
csi_number_get_value (&array->stack.objects[1]),
csi_number_get_value (&array->stack.objects[2]),
csi_number_get_value (&array->stack.objects[3]),
csi_number_get_value (&array->stack.objects[4]),
csi_number_get_value (&array->stack.objects[5]));
obj->type = CSI_OBJECT_TYPE_MATRIX;
obj->datum.matrix = matrix;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_matrix_new_from_matrix (csi_t *ctx,
csi_object_t *obj,
const cairo_matrix_t *m)
{
csi_matrix_t *matrix;
matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
if (_csi_unlikely (matrix == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
matrix->base.ref = 1;
matrix->matrix = *m;
obj->type = CSI_OBJECT_TYPE_MATRIX;
obj->datum.matrix = matrix;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_matrix_new_from_values (csi_t *ctx,
csi_object_t *obj,
double v[6])
{
csi_matrix_t *matrix;
matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
if (_csi_unlikely (matrix == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
matrix->base.ref = 1;
cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]);
obj->type = CSI_OBJECT_TYPE_MATRIX;
obj->datum.matrix = matrix;
return CSI_STATUS_SUCCESS;
}
void
csi_matrix_free (csi_t *ctx,
csi_matrix_t *obj)
{
_csi_slab_free (ctx, obj, sizeof (csi_matrix_t));
}
csi_status_t
csi_name_new (csi_t *ctx,
csi_object_t *obj,
const char *str,
int len)
{
csi_status_t status;
status = _csi_intern_string (ctx, &str, len);
if (_csi_unlikely (status))
return status;
obj->type = CSI_OBJECT_TYPE_NAME;
obj->datum.name = (csi_name_t) str;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_name_new_static (csi_t *ctx,
csi_object_t *obj,
const char *str)
{
csi_status_t status;
status = _csi_intern_string (ctx, &str, -1);
if (_csi_unlikely (status))
return status;
obj->type = CSI_OBJECT_TYPE_NAME;
obj->datum.name = (csi_name_t) str;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_operator_new (csi_t *ctx,
csi_object_t *obj,
csi_operator_t op)
{
obj->type = CSI_OBJECT_TYPE_OPERATOR | CSI_OBJECT_ATTR_EXECUTABLE;
obj->datum.op = op;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_real_new (csi_t *ctx,
csi_object_t *obj,
csi_real_t v)
{
obj->type = CSI_OBJECT_TYPE_REAL;
obj->datum.real = v;
return CSI_STATUS_SUCCESS;
}
csi_status_t
csi_string_new (csi_t *ctx,
csi_object_t *obj,
const char *str,
int len)
{
csi_string_t *string;
string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
if (_csi_unlikely (string == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
string->base.type = CSI_OBJECT_TYPE_STRING;
string->base.ref = 1;
if (len < 0)
len = strlen (str);
if (_csi_unlikely (len >= INT32_MAX)) {
_csi_slab_free (ctx, string, sizeof (csi_string_t));
return _csi_error (CSI_STATUS_NO_MEMORY);
}
string->string = _csi_alloc (ctx, len + 1);
if (_csi_unlikely (string->string == NULL)) {
_csi_slab_free (ctx, string, sizeof (csi_string_t));
return _csi_error (CSI_STATUS_NO_MEMORY);
}
memcpy (string->string, str, len);
string->string[len] = '\0';
string->len = len;
obj->type = CSI_OBJECT_TYPE_STRING;
obj->datum.string = string;
return CSI_STATUS_SUCCESS;
}
static inline csi_status_t
_csi_string_execute (csi_t *ctx, csi_string_t *string)
{
csi_status_t status;
csi_object_t obj;
if (_csi_unlikely (string->len == 0))
return CSI_STATUS_SUCCESS;
status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len);
if (_csi_unlikely (status))
return status;
status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file);
csi_object_free (ctx, &obj);
return status;
}
void
csi_string_free (csi_t *ctx, csi_string_t *string)
{
_csi_free (ctx, string->string);
_csi_slab_free (ctx, string, sizeof (csi_string_t));
}
csi_status_t
csi_object_execute (csi_t *ctx, csi_object_t *obj)
{
csi_status_t status;
csi_object_t indirect;
INDIRECT:
switch (obj->type & CSI_OBJECT_TYPE_MASK) {
case CSI_OBJECT_TYPE_NAME:
status = _csi_name_lookup (ctx, obj->datum.name, &indirect);
if (_csi_unlikely (status))
return status;
if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) {
obj = &indirect;
goto INDIRECT;
} else
return _csi_push_ostack_copy (ctx, &indirect);
case CSI_OBJECT_TYPE_OPERATOR:
return obj->datum.op (ctx);
case CSI_OBJECT_TYPE_ARRAY:
return _csi_array_execute (ctx, obj->datum.array);
case CSI_OBJECT_TYPE_FILE:
return _csi_file_execute (ctx, obj->datum.file);
case CSI_OBJECT_TYPE_STRING:
return _csi_string_execute (ctx, obj->datum.string);
default:
return _csi_push_ostack_copy (ctx, obj);
}
}
csi_object_t *
csi_object_reference (csi_object_t *obj)
{
if (CSI_OBJECT_IS_CAIRO (obj)) {
switch (obj->type & CSI_OBJECT_TYPE_MASK) {
case CSI_OBJECT_TYPE_CONTEXT:
cairo_reference (obj->datum.cr);
break;
case CSI_OBJECT_TYPE_FONT:
cairo_font_face_reference (obj->datum.font_face);
break;
case CSI_OBJECT_TYPE_PATTERN:
cairo_pattern_reference (obj->datum.pattern);
break;
case CSI_OBJECT_TYPE_SCALED_FONT:
cairo_scaled_font_reference (obj->datum.scaled_font);
break;
case CSI_OBJECT_TYPE_SURFACE:
cairo_surface_reference (obj->datum.surface);
break;
}
} else if (CSI_OBJECT_IS_COMPOUND (obj)) {
obj->datum.object->ref++;
}
return obj;
}
void
csi_object_free (csi_t *ctx,
csi_object_t *obj)
{
if (CSI_OBJECT_IS_CAIRO (obj)) {
switch (obj->type & CSI_OBJECT_TYPE_MASK) {
case CSI_OBJECT_TYPE_CONTEXT:
cairo_destroy (obj->datum.cr);
break;
case CSI_OBJECT_TYPE_FONT:
cairo_font_face_destroy (obj->datum.font_face);
break;
case CSI_OBJECT_TYPE_PATTERN:
cairo_pattern_destroy (obj->datum.pattern);
break;
case CSI_OBJECT_TYPE_SCALED_FONT:
cairo_scaled_font_destroy (obj->datum.scaled_font);
break;
case CSI_OBJECT_TYPE_SURFACE:
cairo_surface_destroy (obj->datum.surface);
break;
}
} else if (CSI_OBJECT_IS_COMPOUND (obj)) {
if (--obj->datum.object->ref)
return;
switch (obj->type & CSI_OBJECT_TYPE_MASK) {
case CSI_OBJECT_TYPE_ARRAY:
csi_array_free (ctx, obj->datum.array);
break;
case CSI_OBJECT_TYPE_DICTIONARY:
csi_dictionary_free (ctx, obj->datum.dictionary);
break;
case CSI_OBJECT_TYPE_FILE:
_csi_file_free (ctx, obj->datum.file);
break;
case CSI_OBJECT_TYPE_MATRIX:
csi_matrix_free (ctx, obj->datum.matrix);
break;
case CSI_OBJECT_TYPE_STRING:
csi_string_free (ctx, obj->datum.string);
break;
default:
break;
}
}
}
csi_status_t
csi_object_as_file (csi_t *ctx,
csi_object_t *src,
csi_object_t *file)
{
switch ((int) csi_object_get_type (src)) {
case CSI_OBJECT_TYPE_FILE:
*file = *csi_object_reference (src);
return CSI_STATUS_SUCCESS;
case CSI_OBJECT_TYPE_STRING:
return csi_file_new_from_string (ctx, file, src->datum.string);
case CSI_OBJECT_TYPE_ARRAY:
#if 0
if (src->type & CSI_OBJECT_ATTR_EXECUTABLE)
return _csi_file_new_from_procedure (cs, src);
#endif
default:
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
}
}
static int
lexcmp (void const *a, size_t alen,
void const *b, size_t blen)
{
size_t len = alen < blen ? alen : blen;
int cmp = memcmp (a, b, len);
if (cmp)
return cmp;
if (alen == blen)
return 0;
return alen < blen ? -1 : +1;
}
csi_boolean_t
csi_object_eq (csi_object_t *a,
csi_object_t *b)
{
csi_object_type_t atype = csi_object_get_type (a);
csi_object_type_t btype = csi_object_get_type (b);
if (atype == btype) {
switch (atype) {
case CSI_OBJECT_TYPE_BOOLEAN:
return a->datum.boolean == b->datum.boolean;
case CSI_OBJECT_TYPE_INTEGER:
return a->datum.integer == b->datum.integer;
case CSI_OBJECT_TYPE_REAL:
return a->datum.real == b->datum.real;
case CSI_OBJECT_TYPE_NAME:
return a->datum.name == b->datum.name;
case CSI_OBJECT_TYPE_STRING:
return 0 == lexcmp (a->datum.string->string,
a->datum.string->len,
b->datum.string->string,
b->datum.string->len);
case CSI_OBJECT_TYPE_NULL:
case CSI_OBJECT_TYPE_MARK:
return TRUE;
case CSI_OBJECT_TYPE_OPERATOR:
return a->datum.op == b->datum.op;
case CSI_OBJECT_TYPE_ARRAY:
case CSI_OBJECT_TYPE_DICTIONARY:
case CSI_OBJECT_TYPE_FILE:
case CSI_OBJECT_TYPE_MATRIX:
case CSI_OBJECT_TYPE_CONTEXT:
case CSI_OBJECT_TYPE_FONT:
case CSI_OBJECT_TYPE_PATTERN:
case CSI_OBJECT_TYPE_SCALED_FONT:
case CSI_OBJECT_TYPE_SURFACE:
return a->datum.ptr == b->datum.ptr;
}
}
if (atype < btype) {
csi_object_t *c;
csi_object_type_t ctype;
c = a; a = b; b = c;
ctype = atype; atype = btype; btype = ctype;
}
switch ((int) atype) {
case CSI_OBJECT_TYPE_INTEGER:
if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
return a->datum.integer == b->datum.boolean;
}
break;
case CSI_OBJECT_TYPE_REAL:
if (btype == CSI_OBJECT_TYPE_INTEGER) {
return a->datum.real == b->datum.integer;
}
else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
return a->datum.real == b->datum.boolean;
}
break;
case CSI_OBJECT_TYPE_STRING:
if (btype == CSI_OBJECT_TYPE_NAME) {
const char *bstr = (const char *) b->datum.name;
return 0 == lexcmp (a->datum.string->string,
a->datum.string->len,
bstr,
strlen (bstr));
}
break;
default:
break;
}
return FALSE;
}
csi_status_t
csi_object_compare (csi_object_t *a,
csi_object_t *b,
int *out)
{
csi_object_type_t atype = csi_object_get_type (a);
csi_object_type_t btype = csi_object_get_type (b);
int sign;
if (csi_object_eq (a, b)){
*out = 0;
return CSI_STATUS_SUCCESS;
}
#define CMP(x,y) ((x) < (y) ? -1 : +1)
if (atype == btype) {
switch (atype) {
case CSI_OBJECT_TYPE_BOOLEAN:
*out = CMP (a->datum.boolean, b->datum.boolean);
return CSI_STATUS_SUCCESS;
case CSI_OBJECT_TYPE_INTEGER:
*out = CMP (a->datum.integer, b->datum.integer);
return CSI_STATUS_SUCCESS;
case CSI_OBJECT_TYPE_REAL:
*out = CMP (a->datum.real, b->datum.real);
return CSI_STATUS_SUCCESS;
case CSI_OBJECT_TYPE_NAME: {
const char *x = (char const *) a->datum.name;
const char *y = (char const *) b->datum.name;
*out = lexcmp (x, strlen(x), y, strlen (y));
return CSI_STATUS_SUCCESS;
}
case CSI_OBJECT_TYPE_STRING:
*out = lexcmp (a->datum.string->string,
a->datum.string->len,
b->datum.string->string,
b->datum.string->len);
return CSI_STATUS_SUCCESS;
case CSI_OBJECT_TYPE_NULL:
case CSI_OBJECT_TYPE_MARK:
case CSI_OBJECT_TYPE_OPERATOR:
case CSI_OBJECT_TYPE_ARRAY:
case CSI_OBJECT_TYPE_DICTIONARY:
case CSI_OBJECT_TYPE_FILE:
case CSI_OBJECT_TYPE_MATRIX:
case CSI_OBJECT_TYPE_CONTEXT:
case CSI_OBJECT_TYPE_FONT:
case CSI_OBJECT_TYPE_PATTERN:
case CSI_OBJECT_TYPE_SCALED_FONT:
case CSI_OBJECT_TYPE_SURFACE:
goto TYPE_CHECK_ERROR;
}
}
sign = +1;
if (atype < btype) {
csi_object_t *c;
csi_object_type_t ctype;
c = a; a = b; b = c;
ctype = atype; atype = btype; btype = ctype;
sign = -1;
}
switch ((int) atype) {
case CSI_OBJECT_TYPE_INTEGER:
if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
*out = sign * CMP (a->datum.integer, !!b->datum.boolean);
return CSI_STATUS_SUCCESS;
}
break;
case CSI_OBJECT_TYPE_REAL:
if (btype == CSI_OBJECT_TYPE_INTEGER) {
*out = sign * CMP (a->datum.real, b->datum.integer);
return CSI_STATUS_SUCCESS;
}
else if (btype == CSI_OBJECT_TYPE_BOOLEAN) {
*out = sign * CMP (a->datum.real, !!b->datum.boolean);
return CSI_STATUS_SUCCESS;
}
break;
case CSI_OBJECT_TYPE_STRING:
if (btype == CSI_OBJECT_TYPE_NAME) {
const char *bstr = (const char *) b->datum.name;
*out = sign * lexcmp (a->datum.string->string,
a->datum.string->len,
bstr,
strlen (bstr));
return CSI_STATUS_SUCCESS;
}
break;
default:
break;
}
#undef CMP
TYPE_CHECK_ERROR:
return _csi_error (CSI_STATUS_SCRIPT_INVALID_TYPE);
}