diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c index bf00b15df..7fe196d69 100644 --- a/util/cairo-script/cairo-script-objects.c +++ b/util/cairo-script/cairo-script-objects.c @@ -756,3 +756,106 @@ csi_object_eq (csi_object_t *a, 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); +} diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index 63b3aebd6..e5b6b2d3d 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -1885,45 +1885,21 @@ _for (csi_t *ctx) static csi_status_t _ge (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (csi_object_get_type (a) != csi_object_get_type (b)) { - if (csi_object_is_number (a) && csi_object_is_number (b)) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia >= ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean >= b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer >= b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real >= b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) >= 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) >= 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp >= 0); } static csi_status_t @@ -2335,45 +2311,21 @@ _gray (csi_t *ctx) static csi_status_t _gt (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))){ - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia > ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean > b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer > b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real > b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) > 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) > 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp > 0); } static csi_status_t @@ -2863,45 +2815,21 @@ _index (csi_t *ctx) static csi_status_t _le (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia <= ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean <= b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer <= b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real <= b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) <= 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) <= 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp <= 0); } static csi_status_t @@ -2962,45 +2890,21 @@ _line_to (csi_t *ctx) static csi_status_t _lt (csi_t *ctx) { + csi_status_t status; csi_object_t *a, *b; - csi_boolean_t v; + int cmp; check (2); b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) { - if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) { - double ia, ib; - ia = csi_number_get_value (a); - ib = csi_number_get_value (b); - v = ia < ib; - } else { - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.boolean < b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.integer < b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.real < b->datum.real; - break; - case CSI_OBJECT_TYPE_STRING: - v = strcmp (a->datum.string->string, b->datum.string->string) < 0; - break; - case CSI_OBJECT_TYPE_NAME: - v = strcmp ((char *) a->datum.name, (char *) b->datum.name) < 0; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; pop (2); - return _csi_push_ostack_boolean (ctx, v); + return _csi_push_ostack_boolean (ctx, cmp < 0); } static csi_status_t diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h index 819f25c3f..1952cbec4 100644 --- a/util/cairo-script/cairo-script-private.h +++ b/util/cairo-script/cairo-script-private.h @@ -720,6 +720,11 @@ csi_private csi_boolean_t csi_object_eq (csi_object_t *a, csi_object_t *b); +csi_private csi_status_t +csi_object_compare (csi_object_t *a, + csi_object_t *b, + int *out_cmp); + /* cairo-script-operators.c */ csi_private const csi_operator_def_t *