From 1aeb96dc287b516955db1909995e45fe26d4f87a Mon Sep 17 00:00:00 2001 From: M Joonas Pihlaja Date: Mon, 8 Dec 2008 10:03:57 +0200 Subject: [PATCH] [script] Implement PostScript-like semantics for the eq operator. The eq operator would only work for some types and put the interpreter in an error state if passed objects it didn't know how to compare. It would also not compare strings by value nor allow strings to be compared to names. This patch makes any two objects comparable. --- util/cairo-script/cairo-script-objects.c | 92 ++++++++++++++++++++++ util/cairo-script/cairo-script-operators.c | 64 +-------------- util/cairo-script/cairo-script-private.h | 4 + 3 files changed, 97 insertions(+), 63 deletions(-) diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c index f4726cefb..bf00b15df 100644 --- a/util/cairo-script/cairo-script-objects.c +++ b/util/cairo-script/cairo-script-objects.c @@ -664,3 +664,95 @@ csi_object_as_file (csi_t *ctx, 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; +} diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c index cde54c2a9..13bfc82f0 100644 --- a/util/cairo-script/cairo-script-operators.c +++ b/util/cairo-script/cairo-script-operators.c @@ -1210,69 +1210,7 @@ _eq (csi_t *ctx) b = _csi_peek_ostack (ctx, 0); a = _csi_peek_ostack (ctx, 1); - if (csi_object_get_type (a) != csi_object_get_type (b)) { - switch ((int) csi_object_get_type (a)) { - case CSI_OBJECT_TYPE_BOOLEAN: - switch ((int) csi_object_get_type (b)) { - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.boolean == !! b->datum.integer; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.boolean == (b->datum.real != 0); - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - break; - - case CSI_OBJECT_TYPE_INTEGER: - switch ((int) csi_object_get_type (b)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.integer == b->datum.boolean; - break; - case CSI_OBJECT_TYPE_REAL: - v = a->datum.integer == b->datum.real; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - break; - - case CSI_OBJECT_TYPE_REAL: - switch ((int) csi_object_get_type (b)) { - case CSI_OBJECT_TYPE_BOOLEAN: - v = a->datum.real == b->datum.boolean; - break; - case CSI_OBJECT_TYPE_INTEGER: - v = a->datum.real == b->datum.integer; - break; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - break; - - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } else { - if (CSI_OBJECT_IS_CAIRO (a)) { - v = a->datum.ptr == b->datum.ptr; - } else if (CSI_OBJECT_IS_COMPOUND (a)) { - v = a->datum.object == b->datum.object; - } 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; - default: - return _csi_error (CSI_STATUS_INVALID_SCRIPT); - } - } + v = csi_object_eq (a, b); pop (2); return _csi_push_ostack_boolean (ctx, v); diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h index 8ab1f63a6..819f25c3f 100644 --- a/util/cairo-script/cairo-script-private.h +++ b/util/cairo-script/cairo-script-private.h @@ -716,6 +716,10 @@ csi_object_as_file (csi_t *ctx, csi_object_t *src, csi_object_t *file); +csi_private csi_boolean_t +csi_object_eq (csi_object_t *a, + csi_object_t *b); + /* cairo-script-operators.c */ csi_private const csi_operator_def_t *