mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-06-19 11:18:30 +02:00
[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.
This commit is contained in:
parent
620028fd19
commit
1aeb96dc28
3 changed files with 97 additions and 63 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue