mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-26 11:10:11 +01:00
Add CairoScript interpreter
Add a CairoScript interpreter library and use it to replay the test output for the CairoScript backend. The library is also used by the currently standalone Sphinx debugger [git://anongit.freedesktop.org/~ickle/sphinx]. The syntax/operator semantics are not yet finalized, but are expected to mature before the next stable release.
This commit is contained in:
parent
a856371bef
commit
cdfffc7420
15 changed files with 10801 additions and 33 deletions
20
configure.ac
20
configure.ac
|
|
@ -236,18 +236,12 @@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
any2ppm_cs=no
|
||||
CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [
|
||||
test_script="yes"
|
||||
csi_CFLAGS=
|
||||
csi_LIBS=-lcairo-script-interpreter
|
||||
if test "x$test_script" = "xyes"; then
|
||||
AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1,
|
||||
[Define to 1 if the CairoScript backend can be tested])
|
||||
else
|
||||
AC_MSG_WARN([CairoScript backend will not be tested])
|
||||
fi
|
||||
AC_SUBST(csi_CFLAGS)
|
||||
AC_SUBST(csi_LIBS)
|
||||
test_script=yes
|
||||
any2ppm_cs=yes
|
||||
AC_DEFINE([CAIRO_CAN_TEST_SCRIPT_SURFACE], 1,
|
||||
[Define to 1 if the CairoScript backend can be tested])
|
||||
])
|
||||
|
||||
dnl ===========================================================================
|
||||
|
|
@ -494,7 +488,8 @@ dnl Build the external converter if we have any of the test backends
|
|||
AM_CONDITIONAL(BUILD_ANY2PPM,
|
||||
test "x$any2ppm_svg" = "xyes" \
|
||||
-o "x$any2ppm_pdf" = "xyes" \
|
||||
-o "x$any2ppm_ps" = "xyes")
|
||||
-o "x$any2ppm_ps" = "xyes" \
|
||||
-o "x$any2ppm_cs" = "xyes")
|
||||
|
||||
dnl ===========================================================================
|
||||
dnl The tracing utility requires LD_PRELOAD, so only build it for systems
|
||||
|
|
@ -558,6 +553,7 @@ test/Makefile
|
|||
test/pdiff/Makefile
|
||||
perf/Makefile
|
||||
util/Makefile
|
||||
util/cairo-script/Makefile
|
||||
util/cairo-trace/Makefile
|
||||
util/cairo-trace/cairo-trace
|
||||
doc/Makefile
|
||||
|
|
|
|||
|
|
@ -1170,10 +1170,10 @@ png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
|
|||
|
||||
if BUILD_ANY2PPM
|
||||
check_PROGRAMS += any2ppm
|
||||
any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS) $(csi_CFLAGS)
|
||||
any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS)
|
||||
# add LDADD, so poppler/librsvg uses "our" cairo
|
||||
any2ppm_LDFLAGS = $(CAIRO_TEST_UNDEFINED_LDFLAGS)
|
||||
any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS) $(csi_LIBS)
|
||||
any2ppm_LDADD = $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS)
|
||||
endif
|
||||
|
||||
if CAIRO_CAN_TEST_PDF_SURFACE
|
||||
|
|
|
|||
|
|
@ -171,12 +171,15 @@ write_ppm (cairo_surface_t *surface, int fd)
|
|||
format = cairo_image_surface_get_format (surface);
|
||||
if (format == CAIRO_FORMAT_ARGB32) {
|
||||
/* see if we can convert to a standard ppm type and trim a few bytes */
|
||||
cairo_bool_t uses_alpha = FALSE;
|
||||
const unsigned char *alpha = data;
|
||||
for (j = height * stride; j-- && uses_alpha == FALSE; alpha += 4)
|
||||
uses_alpha = *alpha != 0xff;
|
||||
if (! uses_alpha)
|
||||
format = CAIRO_FORMAT_RGB24;
|
||||
for (j = height; j--; alpha += stride) {
|
||||
for (i = 0; i < width; i++) {
|
||||
if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
format = CAIRO_FORMAT_RGB24;
|
||||
done: ;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
|
|
@ -236,14 +239,12 @@ write_ppm (cairo_surface_t *surface, int fd)
|
|||
#if CAIRO_CAN_TEST_SCRIPT_SURFACE
|
||||
static cairo_surface_t *
|
||||
_create_image (void *closure,
|
||||
double width, double height,
|
||||
csi_object_t *dictionary)
|
||||
double width, double height)
|
||||
//csi_object_t *dictionary)
|
||||
{
|
||||
cairo_surface_t **out = closure;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
return *out = cairo_surface_reference (surface);
|
||||
*out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
return cairo_surface_reference (*out);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -253,17 +254,21 @@ _cairo_script_render_page (const char *filename,
|
|||
cairo_script_interpreter_t *csi;
|
||||
cairo_surface_t *surface = NULL;
|
||||
cairo_status_t status;
|
||||
const cairo_script_interpreter_hooks_t hooks = {
|
||||
.closure = &surface,
|
||||
.surface_create = _create_image,
|
||||
};
|
||||
|
||||
csi = csi_create ();
|
||||
csi_set_surface_create_function (csi, _create_image, &surface);
|
||||
csi_run (csi, filename);
|
||||
status = csi_destroy (csi);
|
||||
if (status || surface == NULL) {
|
||||
cairo_surface_destroy (surface);
|
||||
csi = cairo_script_interpreter_create ();
|
||||
cairo_script_interpreter_install_hooks (csi, &hooks);
|
||||
cairo_script_interpreter_run (csi, filename);
|
||||
status = cairo_script_interpreter_destroy (csi);
|
||||
if (surface == NULL) {
|
||||
return "cairo-script interpreter failed";
|
||||
}
|
||||
|
||||
status = cairo_surface_status (surface);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
status = cairo_surface_status (surface);
|
||||
if (status) {
|
||||
cairo_surface_destroy (surface);
|
||||
return cairo_status_to_string (status);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
include $(top_srcdir)/build/Makefile.am.common
|
||||
|
||||
SUBDIRS = .
|
||||
SUBDIRS = . cairo-script
|
||||
|
||||
if BUILD_TRACE
|
||||
SUBDIRS += cairo-trace
|
||||
|
|
|
|||
17
util/cairo-script/COPYING
Normal file
17
util/cairo-script/COPYING
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Cairo is free software.
|
||||
|
||||
Every source file in the implementation of cairo is available to be
|
||||
redistributed and/or modified under the terms of either the GNU Lesser
|
||||
General Public License (LGPL) version 2.1 or the Mozilla Public
|
||||
License (MPL) version 1.1. Some files are available under more
|
||||
liberal terms, but we believe that in all cases, each file may be used
|
||||
under either the LGPL or the MPL.
|
||||
|
||||
See the following files in this directory for the precise terms and
|
||||
conditions of either license:
|
||||
|
||||
COPYING-LGPL-2.1
|
||||
COPYING-MPL-1.1
|
||||
|
||||
Please see each file in the implementation for copyright and licensing
|
||||
information, (in the opening comment of each file).
|
||||
21
util/cairo-script/Makefile.am
Normal file
21
util/cairo-script/Makefile.am
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
lib_LTLIBRARIES = libcairo-script-interpreter.la
|
||||
|
||||
cairoincludedir=$(includedir)/cairo
|
||||
cairoinclude_HEADERS = cairo-script-interpreter.h
|
||||
libcairo_script_interpreter_la_SOURCES = \
|
||||
cairo-script-private.h \
|
||||
cairo-script-file.c \
|
||||
cairo-script-hash.c \
|
||||
cairo-script-interpreter.c \
|
||||
cairo-script-objects.c \
|
||||
cairo-script-operators.c \
|
||||
cairo-script-scanner.c \
|
||||
cairo-script-stack.c \
|
||||
$(NULL)
|
||||
libcairo_script_interpreter_la_CPPFLAGS = -I$(top_srcdir)/src
|
||||
libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS)
|
||||
libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
|
||||
libcairo_script_interpreter_la_LIBADD = -lz $(CAIRO_LIBS) -L$(top_builddir)/src -lcairo
|
||||
|
||||
EXTRA_DIST = \
|
||||
COPYING
|
||||
1018
util/cairo-script/cairo-script-file.c
Normal file
1018
util/cairo-script/cairo-script-file.c
Normal file
File diff suppressed because it is too large
Load diff
448
util/cairo-script/cairo-script-hash.c
Normal file
448
util/cairo-script/cairo-script-hash.c
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2004 Red Hat, Inc.
|
||||
* Copyright © 2005 Red Hat, Inc.
|
||||
*
|
||||
* 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 Red Hat, Inc.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
* Graydon Hoare <graydon@redhat.com>
|
||||
* Carl Worth <cworth@cworth.org>
|
||||
*/
|
||||
|
||||
#include "cairo-script-private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* An entry can be in one of three states:
|
||||
*
|
||||
* FREE: Entry has never been used, terminates all searches.
|
||||
* Appears in the table as a %NULL pointer.
|
||||
*
|
||||
* DEAD: Entry had been live in the past. A dead entry can be reused
|
||||
* but does not terminate a search for an exact entry.
|
||||
* Appears in the table as a pointer to DEAD_ENTRY.
|
||||
*
|
||||
* LIVE: Entry is currently being used.
|
||||
* Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
|
||||
*/
|
||||
|
||||
#define DEAD_ENTRY ((csi_hash_entry_t *) 0x1)
|
||||
|
||||
#define ENTRY_IS_FREE(entry) ((entry) == NULL)
|
||||
#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
|
||||
#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY)
|
||||
|
||||
/* We expect keys will not be destroyed frequently, so our table does not
|
||||
* contain any explicit shrinking code nor any chain-coalescing code for
|
||||
* entries randomly deleted by memory pressure (except during rehashing, of
|
||||
* course). These assumptions are potentially bad, but they make the
|
||||
* implementation straightforward.
|
||||
*
|
||||
* Revisit later if evidence appears that we're using excessive memory from
|
||||
* a mostly-dead table.
|
||||
*
|
||||
* This table is open-addressed with double hashing. Each table size is a
|
||||
* prime chosen to be a little more than double the high water mark for a
|
||||
* given arrangement, so the tables should remain < 50% full. The table
|
||||
* size makes for the "first" hash modulus; a second prime (2 less than the
|
||||
* first prime) serves as the "second" hash modulus, which is co-prime and
|
||||
* thus guarantees a complete permutation of table indices.
|
||||
*
|
||||
* This structure, and accompanying table, is borrowed/modified from the
|
||||
* file xserver/render/glyph.c in the freedesktop.org x server, with
|
||||
* permission (and suggested modification of doubling sizes) by Keith
|
||||
* Packard.
|
||||
*/
|
||||
|
||||
static const csi_hash_table_arrangement_t hash_table_arrangements [] = {
|
||||
{ 16, 43, 41 },
|
||||
{ 32, 73, 71 },
|
||||
{ 64, 151, 149 },
|
||||
{ 128, 283, 281 },
|
||||
{ 256, 571, 569 },
|
||||
{ 512, 1153, 1151 },
|
||||
{ 1024, 2269, 2267 },
|
||||
{ 2048, 4519, 4517 },
|
||||
{ 4096, 9013, 9011 },
|
||||
{ 8192, 18043, 18041 },
|
||||
{ 16384, 36109, 36107 },
|
||||
{ 32768, 72091, 72089 },
|
||||
{ 65536, 144409, 144407 },
|
||||
{ 131072, 288361, 288359 },
|
||||
{ 262144, 576883, 576881 },
|
||||
{ 524288, 1153459, 1153457 },
|
||||
{ 1048576, 2307163, 2307161 },
|
||||
{ 2097152, 4613893, 4613891 },
|
||||
{ 4194304, 9227641, 9227639 },
|
||||
{ 8388608, 18455029, 18455027 },
|
||||
{ 16777216, 36911011, 36911009 },
|
||||
{ 33554432, 73819861, 73819859 },
|
||||
{ 67108864, 147639589, 147639587 },
|
||||
{ 134217728, 295279081, 295279079 },
|
||||
{ 268435456, 590559793, 590559791 }
|
||||
};
|
||||
|
||||
#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements)
|
||||
|
||||
/**
|
||||
* _csi_hash_table_create:
|
||||
* @keys_equal: a function to return %TRUE if two keys are equal
|
||||
*
|
||||
* Creates a new hash table which will use the keys_equal() function
|
||||
* to compare hash keys. Data is provided to the hash table in the
|
||||
* form of user-derived versions of #csi_hash_entry_t. A hash entry
|
||||
* must be able to hold both a key (including a hash code) and a
|
||||
* value. Sometimes only the key will be necessary, (as in
|
||||
* _csi_hash_table_remove), and other times both a key and a value
|
||||
* will be necessary, (as in _csi_hash_table_insert).
|
||||
*
|
||||
* See #csi_hash_entry_t for more details.
|
||||
*
|
||||
* Return value: the new hash table or %NULL if out of memory.
|
||||
**/
|
||||
csi_status_t
|
||||
_csi_hash_table_init (csi_hash_table_t *hash_table,
|
||||
csi_hash_keys_equal_func_t keys_equal)
|
||||
{
|
||||
hash_table->keys_equal = keys_equal;
|
||||
|
||||
hash_table->arrangement = &hash_table_arrangements[0];
|
||||
|
||||
hash_table->entries = calloc (hash_table->arrangement->size,
|
||||
sizeof(csi_hash_entry_t *));
|
||||
if (hash_table->entries == NULL)
|
||||
return _csi_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
hash_table->live_entries = 0;
|
||||
hash_table->iterating = 0;
|
||||
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _csi_hash_table_destroy:
|
||||
* @hash_table: an empty hash table to destroy
|
||||
*
|
||||
* Immediately destroys the given hash table, freeing all resources
|
||||
* associated with it.
|
||||
*
|
||||
* WARNING: The hash_table must have no live entries in it before
|
||||
* _csi_hash_table_destroy is called. It is a fatal error otherwise,
|
||||
* and this function will halt. The rationale for this behavior is to
|
||||
* avoid memory leaks and to avoid needless complication of the API
|
||||
* with destroy notifiy callbacks.
|
||||
*
|
||||
* WARNING: The hash_table must have no running iterators in it when
|
||||
* _csi_hash_table_destroy is called. It is a fatal error otherwise,
|
||||
* and this function will halt.
|
||||
**/
|
||||
void
|
||||
_csi_hash_table_fini (csi_hash_table_t *hash_table)
|
||||
{
|
||||
free (hash_table->entries);
|
||||
}
|
||||
|
||||
static csi_hash_entry_t **
|
||||
_csi_hash_table_lookup_unique_key (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key)
|
||||
{
|
||||
unsigned long table_size, i, idx, step;
|
||||
csi_hash_entry_t **entry;
|
||||
|
||||
table_size = hash_table->arrangement->size;
|
||||
idx = key->hash % table_size;
|
||||
|
||||
entry = &hash_table->entries[idx];
|
||||
if (! ENTRY_IS_LIVE (*entry))
|
||||
return entry;
|
||||
|
||||
i = 1;
|
||||
step = key->hash % hash_table->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
do {
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
|
||||
entry = &hash_table->entries[idx];
|
||||
if (! ENTRY_IS_LIVE (*entry))
|
||||
return entry;
|
||||
} while (++i < table_size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _csi_hash_table_resize:
|
||||
* @hash_table: a hash table
|
||||
*
|
||||
* Resize the hash table if the number of entries has gotten much
|
||||
* bigger or smaller than the ideal number of entries for the current
|
||||
* size.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS if successful or
|
||||
* %CAIRO_STATUS_NO_MEMORY if out of memory.
|
||||
**/
|
||||
static csi_status_t
|
||||
_csi_hash_table_resize (csi_hash_table_t *hash_table)
|
||||
{
|
||||
csi_hash_table_t tmp;
|
||||
unsigned long new_size, i;
|
||||
|
||||
/* This keeps the hash table between 25% and 50% full. */
|
||||
unsigned long high = hash_table->arrangement->high_water_mark;
|
||||
unsigned long low = high >> 2;
|
||||
|
||||
if (hash_table->live_entries >= low && hash_table->live_entries <= high)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
tmp = *hash_table;
|
||||
|
||||
if (hash_table->live_entries > high) {
|
||||
tmp.arrangement = hash_table->arrangement + 1;
|
||||
/* This code is being abused if we can't make a table big enough. */
|
||||
} else { /* hash_table->live_entries < low */
|
||||
/* Can't shrink if we're at the smallest size */
|
||||
if (hash_table->arrangement == &hash_table_arrangements[0])
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
tmp.arrangement = hash_table->arrangement - 1;
|
||||
}
|
||||
|
||||
new_size = tmp.arrangement->size;
|
||||
tmp.entries = calloc (new_size, sizeof (csi_hash_entry_t*));
|
||||
if (tmp.entries == NULL)
|
||||
return _csi_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
for (i = 0; i < hash_table->arrangement->size; ++i) {
|
||||
if (ENTRY_IS_LIVE (hash_table->entries[i])) {
|
||||
*_csi_hash_table_lookup_unique_key (&tmp, hash_table->entries[i])
|
||||
= hash_table->entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
free (hash_table->entries);
|
||||
hash_table->entries = tmp.entries;
|
||||
hash_table->arrangement = tmp.arrangement;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _csi_hash_table_lookup:
|
||||
* @hash_table: a hash table
|
||||
* @key: the key of interest
|
||||
*
|
||||
* Performs a lookup in @hash_table looking for an entry which has a
|
||||
* key that matches @key, (as determined by the keys_equal() function
|
||||
* passed to _csi_hash_table_create).
|
||||
*
|
||||
* Return value: the matching entry, of %NULL if no match was found.
|
||||
**/
|
||||
void *
|
||||
_csi_hash_table_lookup (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key)
|
||||
{
|
||||
csi_hash_entry_t **entry;
|
||||
unsigned long table_size, i, idx, step;
|
||||
|
||||
table_size = hash_table->arrangement->size;
|
||||
idx = key->hash % table_size;
|
||||
entry = &hash_table->entries[idx];
|
||||
|
||||
if (ENTRY_IS_LIVE (*entry)) {
|
||||
if (hash_table->keys_equal (key, *entry))
|
||||
return *entry;
|
||||
} else if (ENTRY_IS_FREE (*entry))
|
||||
return NULL;
|
||||
|
||||
i = 1;
|
||||
step = key->hash % hash_table->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
do {
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
|
||||
entry = &hash_table->entries[idx];
|
||||
if (ENTRY_IS_LIVE (*entry)) {
|
||||
if (hash_table->keys_equal (key, *entry))
|
||||
return *entry;
|
||||
} else if (ENTRY_IS_FREE (*entry))
|
||||
return NULL;
|
||||
} while (++i < table_size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _csi_hash_table_insert:
|
||||
* @hash_table: a hash table
|
||||
* @key_and_value: an entry to be inserted
|
||||
*
|
||||
* Insert the entry #key_and_value into the hash table.
|
||||
*
|
||||
* WARNING: There must not be an existing entry in the hash table
|
||||
* with a matching key.
|
||||
*
|
||||
* WARNING: It is a fatal error to insert an element while
|
||||
* an iterator is running
|
||||
*
|
||||
* Instead of using insert to replace an entry, consider just editing
|
||||
* the entry obtained with _csi_hash_table_lookup. Or if absolutely
|
||||
* necessary, use _csi_hash_table_remove first.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS if successful or
|
||||
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
|
||||
**/
|
||||
csi_status_t
|
||||
_csi_hash_table_insert (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key_and_value)
|
||||
{
|
||||
csi_status_t status;
|
||||
|
||||
hash_table->live_entries++;
|
||||
status = _csi_hash_table_resize (hash_table);
|
||||
if (_csi_unlikely (status)) {
|
||||
/* abort the insert... */
|
||||
hash_table->live_entries--;
|
||||
return status;
|
||||
}
|
||||
|
||||
*_csi_hash_table_lookup_unique_key (hash_table,
|
||||
key_and_value) = key_and_value;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static csi_hash_entry_t **
|
||||
_csi_hash_table_lookup_exact_key (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key)
|
||||
{
|
||||
unsigned long table_size, i, idx, step;
|
||||
csi_hash_entry_t **entry;
|
||||
|
||||
table_size = hash_table->arrangement->size;
|
||||
idx = key->hash % table_size;
|
||||
|
||||
entry = &hash_table->entries[idx];
|
||||
if (*entry == key)
|
||||
return entry;
|
||||
|
||||
i = 1;
|
||||
step = key->hash % hash_table->arrangement->rehash;
|
||||
if (step == 0)
|
||||
step = 1;
|
||||
do {
|
||||
idx += step;
|
||||
if (idx >= table_size)
|
||||
idx -= table_size;
|
||||
|
||||
entry = &hash_table->entries[idx];
|
||||
if (*entry == key)
|
||||
return entry;
|
||||
} while (++i < table_size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* _csi_hash_table_remove:
|
||||
* @hash_table: a hash table
|
||||
* @key: key of entry to be removed
|
||||
*
|
||||
* Remove an entry from the hash table which points to @key.
|
||||
*
|
||||
* Return value: %CAIRO_STATUS_SUCCESS if successful or
|
||||
* %CAIRO_STATUS_NO_MEMORY if out of memory.
|
||||
**/
|
||||
void
|
||||
_csi_hash_table_remove (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key)
|
||||
{
|
||||
*_csi_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY;
|
||||
hash_table->live_entries--;
|
||||
|
||||
/* Check for table resize. Don't do this when iterating as this will
|
||||
* reorder elements of the table and cause the iteration to potentially
|
||||
* skip some elements. */
|
||||
if (hash_table->iterating == 0) {
|
||||
/* This call _can_ fail, but only in failing to allocate new
|
||||
* memory to shrink the hash table. It does leave the table in a
|
||||
* consistent state, and we've already succeeded in removing the
|
||||
* entry, so we don't examine the failure status of this call. */
|
||||
_csi_hash_table_resize (hash_table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _csi_hash_table_foreach:
|
||||
* @hash_table: a hash table
|
||||
* @hash_callback: function to be called for each live entry
|
||||
* @closure: additional argument to be passed to @hash_callback
|
||||
*
|
||||
* Call @hash_callback for each live entry in the hash table, in a
|
||||
* non-specified order.
|
||||
*
|
||||
* Entries in @hash_table may be removed by code executed from @hash_callback.
|
||||
*
|
||||
* Entries may not be inserted to @hash_table, nor may @hash_table
|
||||
* be destroyed by code executed from @hash_callback. The relevant
|
||||
* functions will halt in these cases.
|
||||
**/
|
||||
void
|
||||
_csi_hash_table_foreach (csi_hash_table_t *hash_table,
|
||||
csi_hash_callback_func_t hash_callback,
|
||||
void *closure)
|
||||
{
|
||||
unsigned long i;
|
||||
csi_hash_entry_t *entry;
|
||||
|
||||
if (hash_table == NULL)
|
||||
return;
|
||||
|
||||
/* Mark the table for iteration */
|
||||
++hash_table->iterating;
|
||||
for (i = 0; i < hash_table->arrangement->size; i++) {
|
||||
entry = hash_table->entries[i];
|
||||
if (ENTRY_IS_LIVE(entry))
|
||||
hash_callback (entry, closure);
|
||||
}
|
||||
/* If some elements were deleted during the iteration,
|
||||
* the table may need resizing. Just do this every time
|
||||
* as the check is inexpensive.
|
||||
*/
|
||||
if (--hash_table->iterating == 0) {
|
||||
/* Should we fail to shrink the hash table, it is left unaltered,
|
||||
* and we don't need to propagate the error status. */
|
||||
_csi_hash_table_resize (hash_table);
|
||||
}
|
||||
}
|
||||
473
util/cairo-script/cairo-script-interpreter.c
Normal file
473
util/cairo-script/cairo-script-interpreter.c
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* 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.h>
|
||||
|
||||
#include "cairo-script-private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <byteswap.h>
|
||||
#include <math.h>
|
||||
|
||||
csi_status_t
|
||||
_csi_error (csi_status_t status)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/* XXX track global/local memory, cap etc, mark/sweep GC */
|
||||
void *
|
||||
_csi_alloc (csi_t *ctx, int size)
|
||||
{
|
||||
if (_csi_unlikely (ctx->status))
|
||||
return NULL;
|
||||
|
||||
return malloc (size);
|
||||
}
|
||||
|
||||
void *
|
||||
_csi_alloc0 (csi_t *ctx, int size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = _csi_alloc (ctx, size);
|
||||
if (_csi_likely (ptr != NULL))
|
||||
memset (ptr, 0, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
_csi_realloc (csi_t *ctx, void *ptr, int size)
|
||||
{
|
||||
if (_csi_unlikely (ctx->status))
|
||||
return NULL;
|
||||
|
||||
return realloc (ptr, size);
|
||||
}
|
||||
|
||||
void
|
||||
_csi_free (csi_t *ctx, void *ptr)
|
||||
{
|
||||
if (_csi_unlikely (ptr == NULL))
|
||||
return;
|
||||
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
_csi_slab_alloc (csi_t *ctx, int size)
|
||||
{
|
||||
if (_csi_unlikely (ctx->status))
|
||||
return NULL;
|
||||
|
||||
return malloc (size);
|
||||
}
|
||||
|
||||
void
|
||||
_csi_slab_free (csi_t *ctx, void *ptr, int size)
|
||||
{
|
||||
if (_csi_unlikely (ptr == NULL))
|
||||
return;
|
||||
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
static csi_status_t
|
||||
_add_operator (csi_t *ctx,
|
||||
csi_dictionary_t *dict,
|
||||
const csi_operator_def_t *def)
|
||||
{
|
||||
csi_object_t name;
|
||||
csi_object_t operator;
|
||||
csi_status_t status;
|
||||
|
||||
status = csi_name_new_static (ctx, &name, def->name);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = csi_operator_new (ctx, &operator, def->op);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return csi_dictionary_put (ctx, dict, name.datum.name, &operator);
|
||||
}
|
||||
|
||||
static csi_status_t
|
||||
_add_integer_constant (csi_t *ctx,
|
||||
csi_dictionary_t *dict,
|
||||
const csi_integer_constant_def_t *def)
|
||||
{
|
||||
csi_object_t name;
|
||||
csi_object_t constant;
|
||||
csi_status_t status;
|
||||
|
||||
status = csi_name_new_static (ctx, &name, def->name);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = csi_integer_new (ctx, &constant, def->value);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return csi_dictionary_put (ctx, dict, name.datum.name, &constant);
|
||||
}
|
||||
|
||||
static csi_status_t
|
||||
_init_dictionaries (csi_t *ctx)
|
||||
{
|
||||
csi_status_t status;
|
||||
csi_stack_t *stack;
|
||||
csi_object_t obj;
|
||||
csi_dictionary_t *dict;
|
||||
const csi_operator_def_t *odef;
|
||||
const csi_integer_constant_def_t *idef;
|
||||
|
||||
stack = &ctx->dstack;
|
||||
|
||||
status = _csi_stack_init (ctx, stack, 4);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* systemdict */
|
||||
status = csi_dictionary_new (ctx, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _csi_stack_push (ctx, stack, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
dict = obj.datum.dictionary;
|
||||
|
||||
/* fill systemdict with operators */
|
||||
for (odef = _csi_operators (); odef->name != NULL; odef++) {
|
||||
status = _add_operator (ctx, dict, odef);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* add constants */
|
||||
for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
|
||||
status = _add_integer_constant (ctx, dict, idef);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* and seal */
|
||||
//dict.type &= ~CSI_OBJECT_ATTR_WRITABLE;
|
||||
|
||||
|
||||
/* globaldict */
|
||||
status = csi_dictionary_new (ctx, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
status = _csi_stack_push (ctx, stack, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* userdict */
|
||||
status = csi_dictionary_new (ctx, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
status = _csi_stack_push (ctx, stack, &obj);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* intern string */
|
||||
|
||||
typedef struct _cairo_intern_string {
|
||||
csi_hash_entry_t hash_entry;
|
||||
int len;
|
||||
char *string;
|
||||
} csi_intern_string_t;
|
||||
|
||||
static unsigned long
|
||||
_intern_string_hash (const char *str, int len)
|
||||
{
|
||||
const signed char *p = (const signed char *) str;
|
||||
unsigned int h = *p;
|
||||
|
||||
for (p += 1; --len; p++)
|
||||
h = (h << 5) - h + *p;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_intern_string_equal (const void *_a, const void *_b)
|
||||
{
|
||||
const csi_intern_string_t *a = _a;
|
||||
const csi_intern_string_t *b = _b;
|
||||
|
||||
if (a->len != b->len)
|
||||
return FALSE;
|
||||
|
||||
return memcmp (a->string, b->string, a->len) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_csi_init (csi_t *ctx)
|
||||
{
|
||||
csi_status_t status;
|
||||
|
||||
ctx->status = CSI_STATUS_SUCCESS;
|
||||
ctx->ref_count = 1;
|
||||
|
||||
status = _csi_hash_table_init (&ctx->strings, _intern_string_equal);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
status = _csi_stack_init (ctx, &ctx->ostack, 2048);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
status = _init_dictionaries (ctx);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
status = _csi_scanner_init (ctx, &ctx->scanner);
|
||||
if (status)
|
||||
goto FAIL;
|
||||
|
||||
return;
|
||||
|
||||
FAIL:
|
||||
if (ctx->status == CSI_STATUS_SUCCESS)
|
||||
ctx->status = status;
|
||||
}
|
||||
|
||||
static void
|
||||
_intern_string_pluck (void *entry, void *closure)
|
||||
{
|
||||
csi_t *ctx = closure;
|
||||
|
||||
_csi_hash_table_remove (&ctx->strings, entry);
|
||||
_csi_free (ctx, entry);
|
||||
}
|
||||
|
||||
static void
|
||||
_csi_fini (csi_t *ctx)
|
||||
{
|
||||
_csi_stack_fini (ctx, &ctx->ostack);
|
||||
_csi_stack_fini (ctx, &ctx->dstack);
|
||||
_csi_scanner_fini (ctx, &ctx->scanner);
|
||||
|
||||
_csi_hash_table_foreach (&ctx->strings, _intern_string_pluck, ctx);
|
||||
_csi_hash_table_fini (&ctx->strings);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj)
|
||||
{
|
||||
return csi_dictionary_put (ctx,
|
||||
ctx->dstack.objects[ctx->dstack.len-1].datum.dictionary,
|
||||
name,
|
||||
obj);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ctx->dstack.len; i--; ) {
|
||||
csi_dictionary_t *dict;
|
||||
csi_dictionary_entry_t *entry;
|
||||
|
||||
dict = ctx->dstack.objects[i].datum.dictionary;
|
||||
entry = _csi_hash_table_lookup (&dict->hash_table,
|
||||
(csi_hash_entry_t *) &name);
|
||||
if (entry != NULL) {
|
||||
*obj = entry->value;
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_name_undefine (csi_t *ctx, csi_name_t name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = ctx->dstack.len; --i; ) {
|
||||
if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary,
|
||||
name))
|
||||
{
|
||||
csi_dictionary_remove (ctx,
|
||||
ctx->dstack.objects[i].datum.dictionary,
|
||||
name);
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_intern_string (csi_t *ctx, const char **str_inout, int len)
|
||||
{
|
||||
char *str = (char *) *str_inout;
|
||||
csi_intern_string_t tmpl, *istring;
|
||||
csi_status_t status = CSI_STATUS_SUCCESS;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen (str);
|
||||
tmpl.hash_entry.hash = _intern_string_hash (str, len);
|
||||
tmpl.len = len;
|
||||
tmpl.string = (char *) str;
|
||||
|
||||
istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry);
|
||||
if (istring == NULL) {
|
||||
istring = _csi_alloc (ctx, sizeof (csi_intern_string_t) + len + 1);
|
||||
if (istring != NULL) {
|
||||
istring->hash_entry.hash = tmpl.hash_entry.hash;
|
||||
istring->len = tmpl.len;
|
||||
istring->string = (char *) (istring + 1);
|
||||
memcpy (istring->string, str, len);
|
||||
istring->string[len] = '\0';
|
||||
|
||||
status = _csi_hash_table_insert (&ctx->strings,
|
||||
&istring->hash_entry);
|
||||
if (_csi_unlikely (status)) {
|
||||
_csi_free (ctx, istring);
|
||||
return status;
|
||||
}
|
||||
} else
|
||||
return _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
*str_inout = istring->string;
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Public */
|
||||
|
||||
static csi_t _csi_nil = { -1, CSI_STATUS_NO_MEMORY };
|
||||
|
||||
csi_t *
|
||||
cairo_script_interpreter_create (void)
|
||||
{
|
||||
csi_t *ctx;
|
||||
|
||||
ctx = calloc (1, sizeof (csi_t));
|
||||
if (ctx == NULL)
|
||||
return (csi_t *) &_csi_nil;
|
||||
|
||||
_csi_init (ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_script_interpreter_install_hooks (csi_t *ctx,
|
||||
const csi_hooks_t *hooks)
|
||||
{
|
||||
if (ctx->status)
|
||||
return;
|
||||
|
||||
ctx->hooks = *hooks;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_script_interpreter_run (csi_t *ctx, const char *filename)
|
||||
{
|
||||
csi_object_t file;
|
||||
|
||||
if (ctx->status)
|
||||
return ctx->status;
|
||||
|
||||
ctx->status = csi_file_new (ctx, &file, filename, "r");
|
||||
if (ctx->status)
|
||||
return ctx->status;
|
||||
|
||||
file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
|
||||
|
||||
ctx->status = csi_object_execute (ctx, &file);
|
||||
csi_object_free (ctx, &file);
|
||||
|
||||
return ctx->status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
cairo_script_interpreter_feed_string (csi_t *ctx, const char *line, int len)
|
||||
{
|
||||
csi_object_t file;
|
||||
|
||||
if (ctx->status)
|
||||
return ctx->status;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen (line);
|
||||
ctx->status = csi_file_new_for_bytes (ctx, &file, line, len);
|
||||
if (ctx->status)
|
||||
return ctx->status;
|
||||
|
||||
file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
|
||||
|
||||
ctx->status = csi_object_execute (ctx, &file);
|
||||
csi_object_free (ctx, &file);
|
||||
|
||||
return ctx->status;
|
||||
}
|
||||
|
||||
csi_t *
|
||||
cairo_script_interpreter_reference (csi_t *ctx)
|
||||
{
|
||||
ctx->ref_count++;
|
||||
return ctx;
|
||||
}
|
||||
slim_hidden_def (cairo_script_interpreter_reference);
|
||||
|
||||
cairo_status_t
|
||||
cairo_script_interpreter_destroy (csi_t *ctx)
|
||||
{
|
||||
csi_status_t status;
|
||||
|
||||
status = ctx->status;
|
||||
if (--ctx->ref_count)
|
||||
return status;
|
||||
|
||||
_csi_fini (ctx);
|
||||
free (ctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
slim_hidden_def (cairo_script_interpreter_destroy);
|
||||
104
util/cairo-script/cairo-script-interpreter.h
Normal file
104
util/cairo-script/cairo-script-interpreter.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2008 Chris Wilson
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef CAIRO_SCRIPT_INTERPRETER_H
|
||||
#define CAIRO_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
#if CAIRO_HAS_SCRIPT_SURFACE
|
||||
|
||||
CAIRO_BEGIN_DECLS
|
||||
|
||||
typedef struct _cairo_script_interpreter cairo_script_interpreter_t;
|
||||
|
||||
/* XXX expose csi_dictionary_t and pass to hooks */
|
||||
typedef void
|
||||
(*csi_destroy_func_t) (void *closure,
|
||||
void *ptr);
|
||||
typedef cairo_surface_t *
|
||||
(*csi_surface_create_func_t) (void *closure,
|
||||
double width,
|
||||
double height);
|
||||
typedef cairo_t *
|
||||
(*csi_context_create_func_t) (void *closure,
|
||||
cairo_surface_t *surface);
|
||||
typedef void
|
||||
(*csi_show_page_func_t) (void *closure,
|
||||
cairo_t *cr);
|
||||
|
||||
typedef void
|
||||
(*csi_copy_page_func_t) (void *closure,
|
||||
cairo_t *cr);
|
||||
|
||||
typedef struct _cairo_script_interpreter_hooks {
|
||||
void *closure;
|
||||
csi_surface_create_func_t surface_create;
|
||||
csi_destroy_func_t surface_destroy;
|
||||
csi_context_create_func_t context_create;
|
||||
csi_destroy_func_t context_destroy;
|
||||
csi_show_page_func_t show_page;
|
||||
csi_copy_page_func_t copy_page;
|
||||
} cairo_script_interpreter_hooks_t;
|
||||
|
||||
cairo_public cairo_script_interpreter_t *
|
||||
cairo_script_interpreter_create (void);
|
||||
|
||||
cairo_public void
|
||||
cairo_script_interpreter_install_hooks (cairo_script_interpreter_t *ctx,
|
||||
const cairo_script_interpreter_hooks_t *hooks);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_script_interpreter_run (cairo_script_interpreter_t *ctx,
|
||||
const char *filename);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_script_interpreter_feed_string (cairo_script_interpreter_t *ctx,
|
||||
const char *line,
|
||||
int len);
|
||||
|
||||
cairo_public cairo_script_interpreter_t *
|
||||
cairo_script_interpreter_reference (cairo_script_interpreter_t *ctx);
|
||||
|
||||
cairo_public cairo_status_t
|
||||
cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx);
|
||||
|
||||
CAIRO_END_DECLS
|
||||
|
||||
#else /*CAIRO_HAS_SCRIPT_SURFACE*/
|
||||
# error Cairo was not compiled with support for the CairoScript backend
|
||||
#endif /*CAIRO_HAS_SCRIPT_SURFACE*/
|
||||
|
||||
#endif /*CAIRO_SCRIPT_INTERPRETER_H*/
|
||||
666
util/cairo-script/cairo-script-objects.c
Normal file
666
util/cairo-script/cairo-script-objects.c
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
5791
util/cairo-script/cairo-script-operators.c
Normal file
5791
util/cairo-script/cairo-script-operators.c
Normal file
File diff suppressed because it is too large
Load diff
853
util/cairo-script/cairo-script-private.h
Normal file
853
util/cairo-script/cairo-script-private.h
Normal file
|
|
@ -0,0 +1,853 @@
|
|||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef CAIRO_SCRIPT_PRIVATE_H
|
||||
#define CAIRO_SCRIPT_PRIVATE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cairo-script-interpreter.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL (void *) 0
|
||||
#endif
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#elif HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#elif HAVE_SYS_INT_TYPES_H
|
||||
# include <sys/int_types.h>
|
||||
#elif defined(_MSC_VER)
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# ifndef HAVE_UINT64_T
|
||||
# define HAVE_UINT64_T 1
|
||||
# endif
|
||||
#else
|
||||
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
|
||||
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private
|
||||
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private_no_warn
|
||||
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
|
||||
# define slim_hidden_int_name(name) INT_##name
|
||||
# define slim_hidden_proto1(name, internal) \
|
||||
extern __typeof (name) name \
|
||||
__asm__ (slim_hidden_asmname (internal))
|
||||
# define slim_hidden_def1(name, internal) \
|
||||
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
|
||||
__attribute__((__alias__(slim_hidden_asmname(internal))))
|
||||
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
|
||||
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
|
||||
# define slim_hidden_ulp2(x) #x
|
||||
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
|
||||
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
|
||||
#else
|
||||
# define slim_hidden_proto(name) int _csi_dummy_prototype(void)
|
||||
# define slim_hidden_proto_no_warn(name) int _csi_dummy_prototype(void)
|
||||
# define slim_hidden_def(name) int _csi_dummy_prototype(void)
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#define csi_pure __attribute__((pure))
|
||||
#define csi_const __attribute__((const))
|
||||
#else
|
||||
#define csi_pure
|
||||
#define csi_const
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
|
||||
#define _CSI_BOOLEAN_EXPR(expr) \
|
||||
__extension__ ({ \
|
||||
int _csi_boolean_var_; \
|
||||
if (expr) \
|
||||
_csi_boolean_var_ = 1; \
|
||||
else \
|
||||
_csi_boolean_var_ = 0; \
|
||||
_csi_boolean_var_; \
|
||||
})
|
||||
#define _csi_likely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 1))
|
||||
#define _csi_unlikely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 0))
|
||||
#else
|
||||
#define _csi_likely(expr) (expr)
|
||||
#define _csi_unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, member) \
|
||||
((char *) &((type *) 0)->member - (char *) 0)
|
||||
#endif
|
||||
#define csi_container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *) 0)->member) *mptr__ = (ptr); \
|
||||
(type *) ((char *) mptr__ - offsetof (type, member)); \
|
||||
})
|
||||
#else
|
||||
#define csi_container_of(ptr, type, member) \
|
||||
(type *)((char *) (ptr) - (char *) &((type *)0)->member)
|
||||
#endif
|
||||
|
||||
/* slim_internal.h */
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
|
||||
#define csi_private_no_warn __attribute__((__visibility__("hidden")))
|
||||
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
|
||||
#define csi_private_no_warn __hidden
|
||||
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
|
||||
#define csi_private_no_warn
|
||||
#endif
|
||||
|
||||
#undef ARRAY_LENGTH
|
||||
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
#ifndef WARN_UNUSED_RESULT
|
||||
#define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
/* Add attribute(warn_unused_result) if supported */
|
||||
#define csi_warn WARN_UNUSED_RESULT
|
||||
#define csi_private csi_private_no_warn csi_warn
|
||||
|
||||
#define CSI_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) (c)
|
||||
#else
|
||||
#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) CSI_BITSWAP8(c)
|
||||
#endif
|
||||
|
||||
typedef enum _csi_status {
|
||||
CSI_STATUS_SUCCESS = CAIRO_STATUS_SUCCESS,
|
||||
CSI_STATUS_NO_MEMORY = CAIRO_STATUS_NO_MEMORY,
|
||||
CSI_STATUS_INVALID_RESTORE = CAIRO_STATUS_INVALID_RESTORE,
|
||||
CSI_STATUS_INVALID_POP_GROUP = CAIRO_STATUS_INVALID_POP_GROUP,
|
||||
CSI_STATUS_NO_CURRENT_POINT = CAIRO_STATUS_NO_CURRENT_POINT,
|
||||
CSI_STATUS_INVALID_MATRIX = CAIRO_STATUS_INVALID_MATRIX,
|
||||
CSI_STATUS_INVALID_STATUS = CAIRO_STATUS_INVALID_STATUS,
|
||||
CSI_STATUS_NULL_POINTER = CAIRO_STATUS_NULL_POINTER,
|
||||
CSI_STATUS_INVALID_STRING = CAIRO_STATUS_INVALID_STRING,
|
||||
CSI_STATUS_INVALID_PATH_DATA = CAIRO_STATUS_INVALID_PATH_DATA,
|
||||
CSI_STATUS_READ_ERROR = CAIRO_STATUS_READ_ERROR,
|
||||
CSI_STATUS_WRITE_ERROR = CAIRO_STATUS_WRITE_ERROR,
|
||||
CSI_STATUS_SURFACE_FINISHED = CAIRO_STATUS_SURFACE_FINISHED,
|
||||
CSI_STATUS_SURFACE_TYPE_MISMATCH = CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
|
||||
CSI_STATUS_PATTERN_TYPE_MISMATCH = CAIRO_STATUS_PATTERN_TYPE_MISMATCH,
|
||||
CSI_STATUS_INVALID_CONTENT = CAIRO_STATUS_INVALID_CONTENT,
|
||||
CSI_STATUS_INVALID_FORMAT = CAIRO_STATUS_INVALID_FORMAT,
|
||||
CSI_STATUS_INVALID_VISUAL = CAIRO_STATUS_INVALID_VISUAL,
|
||||
CSI_STATUS_FILE_NOT_FOUND = CAIRO_STATUS_FILE_NOT_FOUND,
|
||||
CSI_STATUS_INVALID_DASH = CAIRO_STATUS_INVALID_DASH,
|
||||
CSI_STATUS_INVALID_DSC_COMMENT = CAIRO_STATUS_INVALID_DSC_COMMENT,
|
||||
CSI_STATUS_INVALID_INDEX = CAIRO_STATUS_INVALID_INDEX,
|
||||
CSI_STATUS_CLIP_NOT_REPRESENTABLE = CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
|
||||
CSI_STATUS_TEMP_FILE_ERROR = CAIRO_STATUS_TEMP_FILE_ERROR,
|
||||
CSI_STATUS_INVALID_STRIDE = CAIRO_STATUS_INVALID_STRIDE,
|
||||
CSI_STATUS_FONT_TYPE_MISMATCH = CAIRO_STATUS_FONT_TYPE_MISMATCH,
|
||||
CSI_STATUS_USER_FONT_IMMUTABLE = CAIRO_STATUS_USER_FONT_IMMUTABLE,
|
||||
CSI_STATUS_USER_FONT_ERROR = CAIRO_STATUS_USER_FONT_ERROR,
|
||||
CSI_STATUS_NEGATIVE_COUNT = CAIRO_STATUS_NEGATIVE_COUNT,
|
||||
CSI_STATUS_INVALID_CLUSTERS = CAIRO_STATUS_INVALID_CLUSTERS,
|
||||
CSI_STATUS_INVALID_SLANT = CAIRO_STATUS_INVALID_SLANT,
|
||||
CSI_STATUS_INVALID_WEIGHT = CAIRO_STATUS_INVALID_WEIGHT,
|
||||
|
||||
/* cairo-script-interpreter specific errors */
|
||||
|
||||
CSI_STATUS_INVALID_SCRIPT,
|
||||
CSI_STATUS_SCRIPT_INVALID_TYPE,
|
||||
CSI_STATUS_SCRIPT_INVALID_INDEX,
|
||||
CSI_STATUS_SCRIPT_UNDEFINED_NAME,
|
||||
|
||||
_CSI_STATUS_SCRIPT_LAST_ERROR,
|
||||
CSI_INT_STATUS_UNSUPPORTED
|
||||
} csi_status_t;
|
||||
|
||||
typedef enum {
|
||||
CSI_OBJECT_TYPE_NULL = 0,
|
||||
|
||||
/* atomics */
|
||||
CSI_OBJECT_TYPE_BOOLEAN,
|
||||
CSI_OBJECT_TYPE_INTEGER,
|
||||
CSI_OBJECT_TYPE_MARK,
|
||||
CSI_OBJECT_TYPE_NAME,
|
||||
CSI_OBJECT_TYPE_OPERATOR,
|
||||
CSI_OBJECT_TYPE_REAL,
|
||||
|
||||
/* compound */
|
||||
CSI_OBJECT_TYPE_ARRAY = 0x8,
|
||||
CSI_OBJECT_TYPE_DICTIONARY,
|
||||
CSI_OBJECT_TYPE_FILE,
|
||||
CSI_OBJECT_TYPE_MATRIX,
|
||||
CSI_OBJECT_TYPE_STRING,
|
||||
|
||||
/* cairo */
|
||||
CSI_OBJECT_TYPE_CONTEXT = 0x10,
|
||||
CSI_OBJECT_TYPE_FONT,
|
||||
CSI_OBJECT_TYPE_PATTERN,
|
||||
CSI_OBJECT_TYPE_SCALED_FONT,
|
||||
CSI_OBJECT_TYPE_SURFACE,
|
||||
} csi_object_type_t;
|
||||
|
||||
#define CSI_OBJECT_IS_ATOM(OBJ) (((OBJ)->type & CSI_OBJECT_TYPE_MASK) < 0x08)
|
||||
#define CSI_OBJECT_IS_COMPOUND(OBJ) ((OBJ)->type & 0x08)
|
||||
#define CSI_OBJECT_IS_CAIRO(OBJ) ((OBJ)->type & 0x10)
|
||||
|
||||
enum { /* attributes */
|
||||
CSI_OBJECT_ATTR_EXECUTABLE = 1 << 6,
|
||||
CSI_OBJECT_ATTR_WRITABLE = 1 << 7,
|
||||
};
|
||||
#define CSI_OBJECT_ATTR_MASK (CSI_OBJECT_ATTR_EXECUTABLE | \
|
||||
CSI_OBJECT_ATTR_WRITABLE)
|
||||
#define CSI_OBJECT_TYPE_MASK (~CSI_OBJECT_ATTR_MASK)
|
||||
|
||||
typedef struct _cairo_script_interpreter csi_t;
|
||||
|
||||
typedef cairo_bool_t csi_boolean_t;
|
||||
typedef csi_status_t (*csi_operator_t) (csi_t *);
|
||||
typedef float csi_real_t;
|
||||
typedef long csi_integer_t;
|
||||
typedef long csi_name_t;
|
||||
typedef struct _csi_array csi_array_t;
|
||||
typedef struct _csi_buffer csi_buffer_t;
|
||||
typedef struct _csi_compound_object csi_compound_object_t;
|
||||
typedef struct _csi_dictionary csi_dictionary_t;
|
||||
typedef struct _csi_file csi_file_t;
|
||||
typedef struct _csi_hash_entry csi_hash_entry_t;
|
||||
typedef struct _csi_hash_table csi_hash_table_t;
|
||||
typedef struct _csi_hash_table_arrangement csi_hash_table_arrangement_t;
|
||||
typedef struct _csi_list csi_list_t;
|
||||
typedef struct _csi_matrix csi_matrix_t;
|
||||
typedef struct _csi_object csi_object_t;
|
||||
typedef struct _csi_scanner csi_scanner_t;
|
||||
typedef struct _csi_stack csi_stack_t;
|
||||
typedef struct _csi_string csi_string_t;
|
||||
|
||||
typedef cairo_bool_t
|
||||
(*csi_hash_predicate_func_t) (void *entry);
|
||||
|
||||
typedef void
|
||||
(*csi_hash_callback_func_t) (void *entry,
|
||||
void *closure);
|
||||
|
||||
typedef cairo_bool_t
|
||||
(*csi_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
|
||||
|
||||
struct _csi_object {
|
||||
csi_object_type_t type;
|
||||
union {
|
||||
cairo_t *cr;
|
||||
cairo_font_face_t *font_face;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
cairo_surface_t *surface;
|
||||
csi_array_t *array;
|
||||
csi_boolean_t boolean;
|
||||
csi_compound_object_t *object;
|
||||
csi_dictionary_t *dictionary;
|
||||
csi_file_t *file;
|
||||
csi_integer_t integer;
|
||||
csi_matrix_t *matrix;
|
||||
csi_operator_t op;
|
||||
csi_name_t name;
|
||||
csi_real_t real;
|
||||
csi_string_t *string;
|
||||
void *ptr;
|
||||
} datum;
|
||||
};
|
||||
|
||||
struct _csi_compound_object {
|
||||
csi_object_type_t type;
|
||||
unsigned int ref;
|
||||
};
|
||||
|
||||
struct _csi_hash_entry {
|
||||
unsigned long hash;
|
||||
};
|
||||
|
||||
struct _csi_hash_table_arrangement {
|
||||
unsigned long high_water_mark;
|
||||
unsigned long size;
|
||||
unsigned long rehash;
|
||||
};
|
||||
|
||||
struct _csi_hash_table {
|
||||
csi_hash_keys_equal_func_t keys_equal;
|
||||
|
||||
const csi_hash_table_arrangement_t *arrangement;
|
||||
csi_hash_entry_t **entries;
|
||||
|
||||
unsigned long live_entries;
|
||||
unsigned long iterating; /* Iterating, no insert, no resize */
|
||||
};
|
||||
|
||||
|
||||
/* simple, embedded doubly-linked links */
|
||||
struct _csi_list {
|
||||
struct _csi_list *next, *prev;
|
||||
};
|
||||
|
||||
struct _csi_buffer {
|
||||
csi_status_t status;
|
||||
|
||||
char *base, *ptr, *end;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct _csi_stack {
|
||||
csi_object_t *objects;
|
||||
csi_integer_t len;
|
||||
csi_integer_t size;
|
||||
};
|
||||
|
||||
struct _csi_array {
|
||||
csi_compound_object_t base;
|
||||
csi_stack_t stack;
|
||||
};
|
||||
|
||||
typedef struct _csi_dictionary_entry {
|
||||
csi_hash_entry_t hash_entry;
|
||||
csi_object_t value;
|
||||
} csi_dictionary_entry_t;
|
||||
|
||||
struct _csi_dictionary {
|
||||
csi_compound_object_t base;
|
||||
csi_hash_table_t hash_table;
|
||||
};
|
||||
|
||||
struct _csi_matrix {
|
||||
csi_compound_object_t base;
|
||||
cairo_matrix_t matrix;
|
||||
};
|
||||
|
||||
struct _csi_string {
|
||||
csi_compound_object_t base;
|
||||
csi_integer_t len;
|
||||
char *string;
|
||||
};
|
||||
|
||||
typedef struct _csi_filter_funcs {
|
||||
int (*filter_getc) (csi_file_t *);
|
||||
void (*filter_putc) (csi_file_t *, int);
|
||||
int (*filter_read) (csi_file_t *, uint8_t *, int);
|
||||
void (*filter_destroy) (csi_t *, void *);
|
||||
} csi_filter_funcs_t;
|
||||
|
||||
struct _csi_file {
|
||||
csi_compound_object_t base;
|
||||
enum {
|
||||
STDIO,
|
||||
BYTES,
|
||||
PROCEDURE,
|
||||
FILTER,
|
||||
} type;
|
||||
void *src;
|
||||
void *data;
|
||||
uint8_t *bp;
|
||||
int rem;
|
||||
const csi_filter_funcs_t *filter;
|
||||
};
|
||||
|
||||
struct _csi_scanner {
|
||||
csi_status_t status;
|
||||
|
||||
enum {
|
||||
NONE,
|
||||
TOKEN,
|
||||
COMMENT,
|
||||
STRING,
|
||||
HEX,
|
||||
BASE85,
|
||||
} state;
|
||||
|
||||
csi_buffer_t buffer;
|
||||
csi_stack_t procedure_stack;
|
||||
csi_object_t build_procedure;
|
||||
|
||||
int string_p;
|
||||
unsigned int accumulator;
|
||||
unsigned int accumulator_count;
|
||||
};
|
||||
|
||||
typedef cairo_script_interpreter_hooks_t csi_hooks_t;
|
||||
|
||||
struct _cairo_script_interpreter {
|
||||
int ref_count;
|
||||
csi_status_t status;
|
||||
|
||||
csi_hooks_t hooks;
|
||||
|
||||
csi_hash_table_t strings;
|
||||
|
||||
csi_stack_t ostack;
|
||||
csi_stack_t dstack;
|
||||
|
||||
csi_scanner_t scanner;
|
||||
|
||||
/* caches of live data */
|
||||
csi_list_t *_images;
|
||||
csi_list_t *_faces;
|
||||
};
|
||||
|
||||
typedef struct _csi_operator_def {
|
||||
const char *name;
|
||||
csi_operator_t op;
|
||||
} csi_operator_def_t;
|
||||
|
||||
typedef struct _csi_integer_constant_def {
|
||||
const char *name;
|
||||
csi_integer_t value;
|
||||
} csi_integer_constant_def_t;
|
||||
|
||||
/* cairo-script-file.c */
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const char *path, const char *mode);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_for_bytes (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const char *bytes,
|
||||
unsigned int length);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_from_string (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_string_t *src);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_ascii85_decode (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_dictionary_t *dict,
|
||||
csi_object_t *src);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_file_new_deflate_decode (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_dictionary_t *dict,
|
||||
csi_object_t *src);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_file_execute (csi_t *ctx, csi_file_t *obj);
|
||||
|
||||
csi_private int
|
||||
csi_file_getc (csi_file_t *obj);
|
||||
|
||||
csi_private int
|
||||
csi_file_read (csi_file_t *obj, void *buf, int len);
|
||||
|
||||
csi_private void
|
||||
csi_file_putc (csi_file_t *obj, int c);
|
||||
|
||||
csi_private void
|
||||
csi_file_flush (csi_file_t *obj);
|
||||
|
||||
csi_private void
|
||||
csi_file_close (csi_t *ctx, csi_file_t *obj);
|
||||
|
||||
csi_private void
|
||||
_csi_file_free (csi_t *ctx, csi_file_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_file_as_string (csi_t *ctx,
|
||||
csi_file_t *file,
|
||||
csi_object_t *obj);
|
||||
|
||||
/* cairo-script-hash.c */
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_hash_table_init (csi_hash_table_t *hash_table,
|
||||
csi_hash_keys_equal_func_t keys_equal);
|
||||
|
||||
csi_private void
|
||||
_csi_hash_table_fini (csi_hash_table_t *hash_table);
|
||||
|
||||
csi_private void *
|
||||
_csi_hash_table_lookup (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_hash_table_insert (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *entry);
|
||||
|
||||
csi_private void
|
||||
_csi_hash_table_remove (csi_hash_table_t *hash_table,
|
||||
csi_hash_entry_t *key);
|
||||
|
||||
csi_private void
|
||||
_csi_hash_table_foreach (csi_hash_table_t *hash_table,
|
||||
csi_hash_callback_func_t hash_callback,
|
||||
void *closure);
|
||||
|
||||
/* cairo-script-interpreter.c */
|
||||
|
||||
csi_private void *
|
||||
_csi_alloc (csi_t *ctx, int size);
|
||||
|
||||
csi_private void *
|
||||
_csi_alloc0 (csi_t *ctx, int size);
|
||||
|
||||
csi_private void *
|
||||
_csi_realloc (csi_t *ctx, void *ptr, int size);
|
||||
|
||||
csi_private void
|
||||
_csi_free (csi_t *ctx, void *ptr);
|
||||
|
||||
csi_private void *
|
||||
_csi_slab_alloc (csi_t *ctx, int size);
|
||||
|
||||
csi_private void
|
||||
_csi_slab_free (csi_t *ctx, void *ptr, int size);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_push_ostack (csi_t *ctx, csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_name_undefine (csi_t *ctx, csi_name_t name);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_intern_string (csi_t *ctx, const char **str_inout, int len);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_error (csi_status_t status);
|
||||
|
||||
/* cairo-script-objects.c */
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_array_new (csi_t *ctx,
|
||||
csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_array_execute (csi_t *ctx, csi_array_t *array);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_array_get (csi_t *ctx,
|
||||
csi_array_t *array,
|
||||
long elem,
|
||||
csi_object_t *value);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_array_put (csi_t *ctx,
|
||||
csi_array_t *array,
|
||||
csi_integer_t elem,
|
||||
csi_object_t *value);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_array_append (csi_t *ctx,
|
||||
csi_array_t *array,
|
||||
csi_object_t *obj);
|
||||
|
||||
csi_private void
|
||||
csi_array_free (csi_t *ctx, csi_array_t *array);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_boolean_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_boolean_t v);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_dictionary_new (csi_t *ctx,
|
||||
csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_dictionary_put (csi_t *ctx,
|
||||
csi_dictionary_t *dict,
|
||||
csi_name_t name,
|
||||
csi_object_t *value);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_dictionary_get (csi_t *ctx,
|
||||
csi_dictionary_t *dict,
|
||||
csi_name_t name,
|
||||
csi_object_t *value);
|
||||
|
||||
csi_private csi_boolean_t
|
||||
csi_dictionary_has (csi_dictionary_t *dict,
|
||||
csi_name_t name);
|
||||
|
||||
csi_private void
|
||||
csi_dictionary_remove (csi_t *ctx,
|
||||
csi_dictionary_t *dict,
|
||||
csi_name_t name);
|
||||
|
||||
csi_private void
|
||||
csi_dictionary_free (csi_t *ctx,
|
||||
csi_dictionary_t *dict);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_integer_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_integer_t v);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_matrix_new (csi_t *ctx,
|
||||
csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_matrix_new_from_array (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_array_t *array);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_matrix_new_from_matrix (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const cairo_matrix_t *m);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_matrix_new_from_values (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
double v[6]);
|
||||
|
||||
csi_private void
|
||||
csi_matrix_free (csi_t *ctx,
|
||||
csi_matrix_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_name_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const char *str,
|
||||
int len);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_name_new_static (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const char *str);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_operator_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_operator_t op);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_real_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
csi_real_t v);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_string_new (csi_t *ctx,
|
||||
csi_object_t *obj,
|
||||
const char *str,
|
||||
int len);
|
||||
|
||||
csi_private void
|
||||
csi_string_free (csi_t *ctx, csi_string_t *string);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_object_execute (csi_t *ctx, csi_object_t *obj);
|
||||
|
||||
csi_private csi_object_t *
|
||||
csi_object_reference (csi_object_t *obj);
|
||||
|
||||
csi_private void
|
||||
csi_object_free (csi_t *ctx,
|
||||
csi_object_t *obj);
|
||||
|
||||
csi_private csi_status_t
|
||||
csi_object_as_file (csi_t *ctx,
|
||||
csi_object_t *src,
|
||||
csi_object_t *file);
|
||||
|
||||
/* cairo-script-operators.c */
|
||||
|
||||
csi_private const csi_operator_def_t *
|
||||
_csi_operators (void);
|
||||
|
||||
csi_private const csi_integer_constant_def_t *
|
||||
_csi_integer_constants (void);
|
||||
|
||||
/* cairo-script-scanner.c */
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src);
|
||||
|
||||
csi_private void
|
||||
_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner);
|
||||
|
||||
/* cairo-script-stack.c */
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size);
|
||||
|
||||
csi_private void
|
||||
_csi_stack_fini (csi_t *ctx, csi_stack_t *stack);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_stack_roll (csi_t *ctx,
|
||||
csi_stack_t *stack,
|
||||
csi_integer_t mod,
|
||||
csi_integer_t n);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj);
|
||||
|
||||
csi_private csi_object_t *
|
||||
_csi_stack_peek (csi_stack_t *stack, csi_integer_t i);
|
||||
|
||||
csi_private void
|
||||
_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count);
|
||||
|
||||
csi_private csi_status_t
|
||||
_csi_stack_exch (csi_stack_t *stack);
|
||||
|
||||
static inline csi_object_type_t
|
||||
csi_object_get_type (const csi_object_t *obj)
|
||||
{
|
||||
return obj->type & CSI_OBJECT_TYPE_MASK;
|
||||
}
|
||||
|
||||
static inline csi_boolean_t
|
||||
csi_object_is_procedure (const csi_object_t *obj)
|
||||
{
|
||||
return obj->type == (CSI_OBJECT_TYPE_ARRAY | CSI_OBJECT_ATTR_EXECUTABLE);
|
||||
}
|
||||
|
||||
static inline csi_boolean_t
|
||||
csi_object_is_number (const csi_object_t *obj)
|
||||
{
|
||||
switch ((int) csi_object_get_type (obj)) {
|
||||
case CSI_OBJECT_TYPE_BOOLEAN:
|
||||
case CSI_OBJECT_TYPE_INTEGER:
|
||||
case CSI_OBJECT_TYPE_REAL:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline double
|
||||
csi_number_get_value (const csi_object_t *obj)
|
||||
{
|
||||
switch ((int) csi_object_get_type (obj)) {
|
||||
case CSI_OBJECT_TYPE_BOOLEAN: return obj->datum.boolean;
|
||||
case CSI_OBJECT_TYPE_INTEGER: return obj->datum.integer;
|
||||
case CSI_OBJECT_TYPE_REAL: return obj->datum.real;
|
||||
default: return 0.;
|
||||
}
|
||||
}
|
||||
|
||||
static inline csi_boolean_t
|
||||
_csi_check_ostack (csi_t *ctx, csi_integer_t count)
|
||||
{
|
||||
return ctx->ostack.len >= count;
|
||||
}
|
||||
|
||||
static inline csi_object_t *
|
||||
_csi_peek_ostack (csi_t *ctx, csi_integer_t i)
|
||||
{
|
||||
return &ctx->ostack.objects[ctx->ostack.len - i -1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
_csi_pop_ostack (csi_t *ctx, csi_integer_t count)
|
||||
{
|
||||
do
|
||||
csi_object_free (ctx, &ctx->ostack.objects[--ctx->ostack.len]);
|
||||
while (--count);
|
||||
}
|
||||
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack_copy (csi_t *ctx, csi_object_t *obj)
|
||||
{
|
||||
return _csi_stack_push (ctx, &ctx->ostack, csi_object_reference (obj));
|
||||
}
|
||||
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack (csi_t *ctx, csi_object_t *obj)
|
||||
{
|
||||
return _csi_stack_push (ctx, &ctx->ostack, obj);
|
||||
}
|
||||
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack_boolean (csi_t *ctx, csi_boolean_t v)
|
||||
{
|
||||
csi_object_t obj;
|
||||
obj.type = CSI_OBJECT_TYPE_BOOLEAN;
|
||||
obj.datum.boolean = v;
|
||||
return _csi_stack_push (ctx, &ctx->ostack, &obj);
|
||||
}
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack_integer (csi_t *ctx, csi_integer_t v)
|
||||
{
|
||||
csi_object_t obj;
|
||||
obj.type = CSI_OBJECT_TYPE_INTEGER;
|
||||
obj.datum.integer = v;
|
||||
return _csi_stack_push (ctx, &ctx->ostack, &obj);
|
||||
}
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack_mark (csi_t *ctx)
|
||||
{
|
||||
csi_object_t obj;
|
||||
obj.type = CSI_OBJECT_TYPE_MARK;
|
||||
return _csi_stack_push (ctx, &ctx->ostack, &obj);
|
||||
}
|
||||
static inline csi_status_t
|
||||
_csi_push_ostack_real (csi_t *ctx, csi_real_t v)
|
||||
{
|
||||
csi_object_t obj;
|
||||
obj.type = CSI_OBJECT_TYPE_REAL;
|
||||
obj.datum.real = v;
|
||||
return _csi_stack_push (ctx, &ctx->ostack, &obj);
|
||||
}
|
||||
|
||||
slim_hidden_proto_no_warn (cairo_script_interpreter_destroy);
|
||||
slim_hidden_proto_no_warn (cairo_script_interpreter_reference);
|
||||
|
||||
#endif /* CAIRO_SCRIPT_PRIVATE_H */
|
||||
1180
util/cairo-script/cairo-script-scanner.c
Normal file
1180
util/cairo-script/cairo-script-scanner.c
Normal file
File diff suppressed because it is too large
Load diff
196
util/cairo-script/cairo-script-stack.c
Normal file
196
util/cairo-script/cairo-script-stack.c
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size)
|
||||
{
|
||||
csi_status_t status = CSI_STATUS_SUCCESS;
|
||||
|
||||
stack->len = 0;
|
||||
stack->size = size;
|
||||
/* assert ((unsigned) size < INT32_MAX / sizeof (csi_object_t)); */
|
||||
stack->objects = _csi_alloc (ctx, stack->size * sizeof (csi_object_t));
|
||||
if (_csi_unlikely (stack->objects == NULL))
|
||||
status = _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
_csi_stack_fini (csi_t *ctx, csi_stack_t *stack)
|
||||
{
|
||||
csi_integer_t n;
|
||||
|
||||
for (n = 0; n < stack->len; n++)
|
||||
csi_object_free (ctx, &stack->objects[n]);
|
||||
|
||||
_csi_free (ctx, stack->objects);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_stack_roll (csi_t *ctx,
|
||||
csi_stack_t *stack,
|
||||
csi_integer_t mod, csi_integer_t n)
|
||||
{
|
||||
csi_object_t stack_copy[128];
|
||||
csi_object_t *copy;
|
||||
csi_integer_t last, i, len;
|
||||
|
||||
switch (mod) { /* special cases */
|
||||
case 1:
|
||||
last = stack->len - 1;
|
||||
stack_copy[0] = stack->objects[last];
|
||||
for (i = last; --n; i--)
|
||||
stack->objects[i] = stack->objects[i-1];
|
||||
stack->objects[i] = stack_copy[0];
|
||||
return CSI_STATUS_SUCCESS;
|
||||
case -1:
|
||||
last = stack->len - 1;
|
||||
stack_copy[0] = stack->objects[i = last - n + 1];
|
||||
for (; --n; i++)
|
||||
stack->objects[i] = stack->objects[i+1];
|
||||
stack->objects[i] = stack_copy[0];
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* fall back to a copy */
|
||||
if (n > ARRAY_LENGTH (stack_copy)) {
|
||||
if (_csi_unlikely ((unsigned) n > INT32_MAX / sizeof (csi_object_t)))
|
||||
return _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
copy = _csi_alloc (ctx, n * sizeof (csi_object_t));
|
||||
if (copy == NULL)
|
||||
return _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
} else
|
||||
copy = stack_copy;
|
||||
|
||||
i = stack->len - n;
|
||||
memcpy (copy, stack->objects + i, n * sizeof (csi_object_t));
|
||||
mod = -mod;
|
||||
if (mod < 0)
|
||||
mod += n;
|
||||
last = mod;
|
||||
for (len = n; n--; i++) {
|
||||
stack->objects[i] = copy[last];
|
||||
if (++last == len)
|
||||
last = 0;
|
||||
}
|
||||
|
||||
if (copy != stack_copy)
|
||||
_csi_free (ctx, copy);
|
||||
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt)
|
||||
{
|
||||
csi_integer_t newsize;
|
||||
csi_object_t *newstack;
|
||||
|
||||
if (_csi_likely (cnt <= stack->size))
|
||||
return CSI_STATUS_SUCCESS;
|
||||
if (_csi_unlikely ((unsigned) cnt >= INT32_MAX / sizeof (csi_object_t)))
|
||||
return _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
|
||||
newsize = stack->size;
|
||||
do {
|
||||
newsize *= 2;
|
||||
} while (newsize <= cnt);
|
||||
|
||||
newstack = _csi_realloc (ctx,
|
||||
stack->objects,
|
||||
newsize * sizeof (csi_object_t));
|
||||
if (_csi_unlikely (newstack == NULL))
|
||||
return _csi_error (CSI_STATUS_NO_MEMORY);
|
||||
|
||||
stack->objects = newstack;
|
||||
stack->size = newsize;
|
||||
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj)
|
||||
{
|
||||
if (_csi_unlikely (stack->len == stack->size)) {
|
||||
csi_status_t status;
|
||||
|
||||
status = _csi_stack_grow (ctx, stack, stack->size + 1);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
stack->objects[stack->len++] = *obj;
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
csi_object_t *
|
||||
_csi_stack_peek (csi_stack_t *stack, csi_integer_t i)
|
||||
{
|
||||
if (_csi_unlikely (stack->len < i))
|
||||
return NULL;
|
||||
|
||||
return &stack->objects[stack->len - i -1];
|
||||
}
|
||||
|
||||
void
|
||||
_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count)
|
||||
{
|
||||
if (_csi_unlikely (stack->len < count))
|
||||
count = stack->len;
|
||||
|
||||
while (count--)
|
||||
csi_object_free (ctx, &stack->objects[--stack->len]);
|
||||
}
|
||||
|
||||
csi_status_t
|
||||
_csi_stack_exch (csi_stack_t *stack)
|
||||
{
|
||||
csi_object_t tmp;
|
||||
csi_integer_t n;
|
||||
|
||||
if (_csi_unlikely (stack->len < 2))
|
||||
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
|
||||
|
||||
n = stack->len - 1;
|
||||
tmp = stack->objects[n];
|
||||
stack->objects[n] = stack->objects[n - 1];
|
||||
stack->objects[n - 1] = tmp;
|
||||
|
||||
return CSI_STATUS_SUCCESS;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue