summaryrefslogtreecommitdiffstats
path: root/plug-ins/script-fu/scheme-wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/script-fu/scheme-wrapper.c')
-rw-r--r--plug-ins/script-fu/scheme-wrapper.c1671
1 files changed, 1671 insertions, 0 deletions
diff --git a/plug-ins/script-fu/scheme-wrapper.c b/plug-ins/script-fu/scheme-wrapper.c
new file mode 100644
index 0000000..69e22c0
--- /dev/null
+++ b/plug-ins/script-fu/scheme-wrapper.c
@@ -0,0 +1,1671 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if 0
+#define DEBUG_MARSHALL 0 /* No need to define this until you need it */
+#define DEBUG_SCRIPTS 0
+#endif
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "libgimp/gimp.h"
+
+#include "tinyscheme/scheme-private.h"
+#if USE_DL
+#include "tinyscheme/dynload.h"
+#endif
+#include "ftx/ftx.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-console.h"
+#include "script-fu-interface.h"
+#include "script-fu-regex.h"
+#include "script-fu-scripts.h"
+#include "script-fu-server.h"
+
+#include "scheme-wrapper.h"
+
+
+#undef cons
+
+static void ts_init_constants (scheme *sc);
+static void ts_init_enum (scheme *sc,
+ GType enum_type);
+static void ts_init_procedures (scheme *sc,
+ gboolean register_scipts);
+static void convert_string (gchar *str);
+static pointer script_fu_marshal_procedure_call (scheme *sc,
+ pointer a,
+ gboolean permissive);
+static pointer script_fu_marshal_procedure_call_strict (scheme *sc,
+ pointer a);
+static pointer script_fu_marshal_procedure_call_permissive (scheme *sc,
+ pointer a);
+static void script_fu_marshal_destroy_args (GimpParam *params,
+ gint n_params);
+
+static pointer script_fu_register_call (scheme *sc,
+ pointer a);
+static pointer script_fu_menu_register_call (scheme *sc,
+ pointer a);
+static pointer script_fu_quit_call (scheme *sc,
+ pointer a);
+static pointer script_fu_nil_call (scheme *sc,
+ pointer a);
+
+static gboolean ts_load_file (const gchar *dirname,
+ const gchar *basename);
+
+typedef struct
+{
+ const gchar *name;
+ gint value;
+} NamedConstant;
+
+static const NamedConstant script_constants[] =
+{
+ /* Useful values from libgimpbase/gimplimits.h */
+ { "MIN-IMAGE-SIZE", GIMP_MIN_IMAGE_SIZE },
+ { "MAX-IMAGE-SIZE", GIMP_MAX_IMAGE_SIZE },
+ { "MIN-RESOLUTION", GIMP_MIN_RESOLUTION },
+ { "MAX-RESOLUTION", GIMP_MAX_RESOLUTION },
+
+ /* Useful misc stuff */
+ { "TRUE", TRUE },
+ { "FALSE", FALSE },
+
+ /* Builtin units */
+ { "UNIT-PIXEL", GIMP_UNIT_PIXEL },
+ { "UNIT-INCH", GIMP_UNIT_INCH },
+ { "UNIT-MM", GIMP_UNIT_MM },
+ { "UNIT-POINT", GIMP_UNIT_POINT },
+ { "UNIT-PICA", GIMP_UNIT_PICA },
+
+ /* Script-Fu types */
+ { "SF-IMAGE", SF_IMAGE },
+ { "SF-DRAWABLE", SF_DRAWABLE },
+ { "SF-LAYER", SF_LAYER },
+ { "SF-CHANNEL", SF_CHANNEL },
+ { "SF-VECTORS", SF_VECTORS },
+ { "SF-COLOR", SF_COLOR },
+ { "SF-TOGGLE", SF_TOGGLE },
+ { "SF-VALUE", SF_VALUE },
+ { "SF-STRING", SF_STRING },
+ { "SF-FILENAME", SF_FILENAME },
+ { "SF-DIRNAME", SF_DIRNAME },
+ { "SF-ADJUSTMENT", SF_ADJUSTMENT },
+ { "SF-FONT", SF_FONT },
+ { "SF-PATTERN", SF_PATTERN },
+ { "SF-BRUSH", SF_BRUSH },
+ { "SF-GRADIENT", SF_GRADIENT },
+ { "SF-OPTION", SF_OPTION },
+ { "SF-PALETTE", SF_PALETTE },
+ { "SF-TEXT", SF_TEXT },
+ { "SF-ENUM", SF_ENUM },
+ { "SF-DISPLAY", SF_DISPLAY },
+
+ /* For SF-ADJUSTMENT */
+ { "SF-SLIDER", SF_SLIDER },
+ { "SF-SPINNER", SF_SPINNER },
+
+ { NULL, 0 }
+};
+
+
+static scheme sc;
+
+
+void
+tinyscheme_init (GList *path,
+ gboolean register_scripts)
+{
+ /* init the interpreter */
+ if (! scheme_init (&sc))
+ {
+ g_message ("Could not initialize TinyScheme!");
+ return;
+ }
+
+ scheme_set_input_port_file (&sc, stdin);
+ scheme_set_output_port_file (&sc, stdout);
+ ts_register_output_func (ts_stdout_output_func, NULL);
+
+ /* Initialize the TinyScheme extensions */
+ init_ftx (&sc);
+ script_fu_regex_init (&sc);
+
+ /* register in the interpreter the gimp functions and types. */
+ ts_init_constants (&sc);
+ ts_init_procedures (&sc, register_scripts);
+
+ if (path)
+ {
+ GList *list;
+
+ for (list = path; list; list = g_list_next (list))
+ {
+ gchar *dir = g_file_get_path (list->data);
+
+ if (ts_load_file (dir, "script-fu.init"))
+ {
+ /* To improve compatibility with older Script-Fu scripts,
+ * load script-fu-compat.init from the same directory.
+ */
+ ts_load_file (dir, "script-fu-compat.init");
+
+ /* To improve compatibility with older GIMP version,
+ * load plug-in-compat.init from the same directory.
+ */
+ ts_load_file (dir, "plug-in-compat.init");
+
+ g_free (dir);
+
+ break;
+ }
+
+ g_free (dir);
+ }
+
+ if (list == NULL)
+ g_printerr ("Unable to read initialization file script-fu.init\n");
+ }
+}
+
+/* Create an SF-RUN-MODE constant for use in scripts.
+ * It is set to the run mode state determined by GIMP.
+ */
+void
+ts_set_run_mode (GimpRunMode run_mode)
+{
+ pointer symbol;
+
+ symbol = sc.vptr->mk_symbol (&sc, "SF-RUN-MODE");
+ sc.vptr->scheme_define (&sc, sc.global_env, symbol,
+ sc.vptr->mk_integer (&sc, run_mode));
+ sc.vptr->setimmutable (symbol);
+}
+
+void
+ts_set_print_flag (gint print_flag)
+{
+ sc.print_output = print_flag;
+}
+
+void
+ts_print_welcome (void)
+{
+ ts_output_string (TS_OUTPUT_NORMAL,
+ "Welcome to TinyScheme, Version 1.40\n", -1);
+ ts_output_string (TS_OUTPUT_NORMAL,
+ "Copyright (c) Dimitrios Souflis\n", -1);
+}
+
+void
+ts_interpret_stdin (void)
+{
+ scheme_load_file (&sc, stdin);
+}
+
+gint
+ts_interpret_string (const gchar *expr)
+{
+#if DEBUG_SCRIPTS
+ sc.print_output = 1;
+ sc.tracing = 1;
+#endif
+
+ sc.vptr->load_string (&sc, (char *) expr);
+
+ return sc.retcode;
+}
+
+const gchar *
+ts_get_success_msg (void)
+{
+ if (sc.vptr->is_string (sc.value))
+ return sc.vptr->string_value (sc.value);
+
+ return "Success";
+}
+
+void
+ts_stdout_output_func (TsOutputType type,
+ const char *string,
+ int len,
+ gpointer user_data)
+{
+ if (len < 0)
+ len = strlen (string);
+ fprintf (stdout, "%.*s", len, string);
+ fflush (stdout);
+}
+
+void
+ts_gstring_output_func (TsOutputType type,
+ const char *string,
+ int len,
+ gpointer user_data)
+{
+ GString *gstr = (GString *) user_data;
+
+ g_string_append_len (gstr, string, len);
+}
+
+
+/* private functions */
+
+/*
+ * Below can be found the functions responsible for registering the
+ * gimp functions and types against the scheme interpreter.
+ */
+static void
+ts_init_constants (scheme *sc)
+{
+ const gchar **enum_type_names;
+ gint n_enum_type_names;
+ gint i;
+ pointer symbol;
+ GQuark quark;
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-data-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_data_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-plug-in-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_plug_in_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-locale-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_locale_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-sysconf-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_sysconf_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ enum_type_names = gimp_enums_get_type_names (&n_enum_type_names);
+ quark = g_quark_from_static_string ("gimp-compat-enum");
+
+ for (i = 0; i < n_enum_type_names; i++)
+ {
+ const gchar *enum_name = enum_type_names[i];
+ GType enum_type = g_type_from_name (enum_name);
+
+ ts_init_enum (sc, enum_type);
+
+ enum_type = (GType) g_type_get_qdata (enum_type, quark);
+
+ if (enum_type)
+ ts_init_enum (sc, enum_type);
+ }
+
+ /* Constants used in the register block of scripts */
+ for (i = 0; script_constants[i].name != NULL; ++i)
+ {
+ symbol = sc->vptr->mk_symbol (sc, script_constants[i].name);
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_integer (sc,
+ script_constants[i].value));
+ sc->vptr->setimmutable (symbol);
+ }
+
+ /* Define string constant for use in building paths to files/directories */
+ symbol = sc->vptr->mk_symbol (sc, "DIR-SEPARATOR");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, G_DIR_SEPARATOR_S));
+ sc->vptr->setimmutable (symbol);
+
+ /* Define string constant for use in building search paths */
+ symbol = sc->vptr->mk_symbol (sc, "SEARCHPATH-SEPARATOR");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, G_SEARCHPATH_SEPARATOR_S));
+ sc->vptr->setimmutable (symbol);
+
+ /* These constants are deprecated and will be removed at a later date. */
+ symbol = sc->vptr->mk_symbol (sc, "gimp-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-data-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_data_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-plugin-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_plug_in_directory ()));
+ sc->vptr->setimmutable (symbol);
+}
+
+static void
+ts_init_enum (scheme *sc,
+ GType enum_type)
+{
+ GEnumClass *enum_class = g_type_class_ref (enum_type);
+ GEnumValue *value;
+
+ for (value = enum_class->values; value->value_name; value++)
+ {
+ if (g_str_has_prefix (value->value_name, "GIMP_"))
+ {
+ gchar *scheme_name;
+ pointer symbol;
+
+ scheme_name = g_strdup (value->value_name + strlen ("GIMP_"));
+ convert_string (scheme_name);
+
+ symbol = sc->vptr->mk_symbol (sc, scheme_name);
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_integer (sc, value->value));
+ sc->vptr->setimmutable (symbol);
+
+ g_free (scheme_name);
+ }
+ }
+
+ g_type_class_unref (enum_class);
+}
+
+static void
+ts_init_procedures (scheme *sc,
+ gboolean register_scripts)
+{
+ gchar **proc_list;
+ gint num_procs;
+ gint i;
+ pointer symbol;
+
+#if USE_DL
+ symbol = sc->vptr->mk_symbol (sc,"load-extension");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc, scm_load_ext));
+ sc->vptr->setimmutable (symbol);
+#endif
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-register");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ register_scripts ?
+ script_fu_register_call :
+ script_fu_nil_call));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-menu-register");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ register_scripts ?
+ script_fu_menu_register_call :
+ script_fu_nil_call));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-quit");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc, script_fu_quit_call));
+ sc->vptr->setimmutable (symbol);
+
+ /* register the database execution procedure */
+ symbol = sc->vptr->mk_symbol (sc, "gimp-proc-db-call");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ script_fu_marshal_procedure_call_strict));
+ sc->vptr->setimmutable (symbol);
+
+ /* register the internal database execution procedure; see comment below */
+ symbol = sc->vptr->mk_symbol (sc, "-gimp-proc-db-call");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ script_fu_marshal_procedure_call_permissive));
+ sc->vptr->setimmutable (symbol);
+
+ gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*",
+ &num_procs, &proc_list);
+
+ /* Register each procedure as a scheme func */
+ for (i = 0; i < num_procs; i++)
+ {
+ gchar *buff;
+
+ /* Build a define that will call the foreign function.
+ * The Scheme statement was suggested by Simon Budig.
+ *
+ * We call the procedure through -gimp-proc-db-call, which is a more
+ * permissive version of gimp-proc-db-call, that accepts (and ignores)
+ * any number of arguments for nullary procedures, for backward
+ * compatibility.
+ */
+ buff = g_strdup_printf (" (define (%s . args)"
+ " (apply -gimp-proc-db-call \"%s\" args))",
+ proc_list[i], proc_list[i]);
+
+ /* Execute the 'define' */
+ sc->vptr->load_string (sc, buff);
+
+ g_free (buff);
+ }
+
+ g_strfreev (proc_list);
+}
+
+static gboolean
+ts_load_file (const gchar *dirname,
+ const gchar *basename)
+{
+ gchar *filename;
+ FILE *fin;
+
+ filename = g_build_filename (dirname, basename, NULL);
+
+ fin = g_fopen (filename, "rb");
+
+ g_free (filename);
+
+ if (fin)
+ {
+ scheme_load_file (&sc, fin);
+ fclose (fin);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+convert_string (gchar *str)
+{
+ while (*str)
+ {
+ if (*str == '_') *str = '-';
+ str++;
+ }
+}
+
+/* This is called by the Scheme interpreter to allow calls to GIMP functions */
+static pointer
+script_fu_marshal_procedure_call (scheme *sc,
+ pointer a,
+ gboolean permissive)
+{
+ GimpParam *args;
+ GimpParam *values = NULL;
+ gint nvalues;
+ gchar *proc_name;
+ gchar *proc_blurb;
+ gchar *proc_help;
+ gchar *proc_author;
+ gchar *proc_copyright;
+ gchar *proc_date;
+ GimpPDBProcType proc_type;
+ gint nparams;
+ gint nreturn_vals;
+ GimpParamDef *params;
+ GimpParamDef *return_vals;
+ gchar error_str[1024];
+ gint i;
+ gint success = TRUE;
+ pointer return_val = sc->NIL;
+
+#if DEBUG_MARSHALL
+/* These three #defines are from Tinyscheme (tinyscheme/scheme.c) */
+#define T_MASKTYPE 31
+#define typeflag(p) ((p)->_flag)
+#define type(p) (typeflag(p)&T_MASKTYPE)
+
+ static const char *ts_types[] =
+ {
+ "T_NONE",
+ "T_STRING", "T_NUMBER", "T_SYMBOL", "T_PROC",
+ "T_PAIR", "T_CLOSURE", "T_CONTINUATION", "T_FOREIGN",
+ "T_CHARACTER", "T_PORT", "T_VECTOR", "T_MACRO",
+ "T_PROMISE", "T_ENVIRONMENT","T_ARRAY"
+ };
+
+ g_printerr ("\nIn %s()\n", G_STRFUNC);
+#endif
+
+ /* Make sure there are arguments */
+ if (a == sc->NIL)
+ return foreign_error (sc,
+ "Procedure argument marshaller was called with no arguments. "
+ "The procedure to be executed and the arguments it requires "
+ "(possibly none) must be specified.", 0);
+
+ /* The PDB procedure name is the argument or first argument of the list */
+ if (sc->vptr->is_pair (a))
+ proc_name = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+ else
+ proc_name = g_strdup (sc->vptr->string_value (a));
+
+#ifdef DEBUG_MARSHALL
+ g_printerr (" proc name: %s\n", proc_name);
+ g_printerr (" parms rcvd: %d\n", sc->vptr->list_length (sc, a)-1);
+#endif
+
+ /* report the current command */
+ script_fu_interface_report_cc (proc_name);
+
+ /* Attempt to fetch the procedure from the database */
+ if (! gimp_procedural_db_proc_info (proc_name,
+ &proc_blurb,
+ &proc_help,
+ &proc_author,
+ &proc_copyright,
+ &proc_date,
+ &proc_type,
+ &nparams, &nreturn_vals,
+ &params, &return_vals))
+ {
+#ifdef DEBUG_MARSHALL
+ g_printerr (" Invalid procedure name\n");
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid procedure name %s specified", proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Free the name and the description which are of no use here. */
+ for (i = 0; i < nparams; i++)
+ {
+ g_free (params[i].name);
+ g_free (params[i].description);
+ }
+ for (i = 0; i < nreturn_vals; i++)
+ {
+ g_free (return_vals[i].name);
+ g_free (return_vals[i].description);
+ }
+
+ /* Check the supplied number of arguments */
+ if ((nparams > 0 || ! permissive) &&
+ (sc->vptr->list_length (sc, a) - 1) != nparams)
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Invalid number of arguments (expected %d but received %d)",
+ nparams, (sc->vptr->list_length (sc, a) - 1));
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid number of arguments for %s (expected %d but received %d)",
+ proc_name, nparams, (sc->vptr->list_length (sc, a) - 1));
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Marshall the supplied arguments */
+ if (nparams)
+ args = g_new (GimpParam, nparams);
+ else
+ args = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ gint32 n_elements;
+ pointer vector;
+ gint j;
+
+ a = sc->vptr->pair_cdr (a);
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *type_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE,
+ params[i].type,
+ &type_name, NULL, NULL, NULL);
+
+ g_printerr (" param %d - expecting type %s (%d)\n",
+ i + 1, type_name, params[i].type);
+ g_printerr (" passed arg is type %s (%d)\n",
+ ts_types[ type(sc->vptr->pair_car (a)) ],
+ type(sc->vptr->pair_car (a)));
+ }
+#endif
+
+ args[i].type = params[i].type;
+
+ switch (params[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int32 = sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int32 arg is '%d'\n", args[i].data.d_int32);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT16:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int16 = (gint16) sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int16 arg is '%d'\n", args[i].data.d_int16);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT8:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int8 = (guint8) sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int8 arg is '%u'\n", args[i].data.d_int8);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_FLOAT:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_float = sc->vptr->rvalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" float arg is '%f'\n", args[i].data.d_float);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STRING:
+ if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_string = sc->vptr->string_value (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" string arg is '%s'\n", args[i].data.d_string);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT32 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int32array = g_new (gint32, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ /* FIXME: Check values in vector stay within range for each type. */
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int32array[j] =
+ (gint32) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int32 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 || n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT16 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name, sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int16array = g_new (gint16, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int16array[j] =
+ (gint16) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int16 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT8 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int8array = g_new (guint8, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int8array[j] =
+ (guint8) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int8 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "FLOAT vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_floatarray = g_new (gdouble, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_floatarray[j] =
+ (gfloat) sc->vptr->rvalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" float vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %f",
+ sc->vptr->rvalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ vector = sc->vptr->pair_car (a); /* vector is pointing to a list */
+ if (!sc->vptr->is_list (sc, vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i - 1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->list_length (sc, vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "STRING vector (argument %d) for function %s has "
+ "length of %d but expected length of %d",
+ i+1, proc_name,
+ sc->vptr->list_length (sc, vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_stringarray = g_new (gchar *, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->pair_car (vector);
+
+ if (!sc->vptr->is_string (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a string (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_stringarray[j] =
+ (gchar *) sc->vptr->string_value (v_element);
+
+ vector = sc->vptr->pair_cdr (vector);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->list_length ( sc, sc->vptr->pair_car (a) );
+ g_printerr (" string vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" \"%s\"",
+ args[i].data.d_stringarray[j]);
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_COLOR:
+ if (sc->vptr->is_string (sc->vptr->pair_car (a)))
+ {
+ if (! gimp_rgb_parse_css (&args[i].data.d_color,
+ sc->vptr->string_value (sc->vptr->pair_car (a)),
+ -1))
+ success = FALSE;
+
+ gimp_rgb_set_alpha (&args[i].data.d_color, 1.0);
+#if DEBUG_MARSHALL
+ g_printerr (" (%s)\n",
+ sc->vptr->string_value (sc->vptr->pair_car (a)));
+#endif
+ }
+ else if (sc->vptr->is_list (sc, sc->vptr->pair_car (a)) &&
+ sc->vptr->list_length (sc, sc->vptr->pair_car (a)) == 3)
+ {
+ pointer color_list;
+ guchar r = 0, g = 0, b = 0;
+
+ color_list = sc->vptr->pair_car (a);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ color_list = sc->vptr->pair_cdr (color_list);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ color_list = sc->vptr->pair_cdr (color_list);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ if (success)
+ gimp_rgba_set_uchar (&args[i].data.d_color, r, g, b, 255);
+#if DEBUG_MARSHALL
+ if (success)
+ g_printerr (" (%d %d %d)\n", r, g, b);
+ else
+ g_printerr (" COLOR list contains non-numbers\n");
+#endif
+ }
+ else
+ {
+ success = FALSE;
+ }
+ break;
+
+ case GIMP_PDB_COLORARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "COLOR vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_colorarray = g_new (GimpRGB, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+ pointer color_list;
+ guchar r, g, b;
+
+ if (! (sc->vptr->is_list (sc,
+ sc->vptr->pair_car (v_element)) &&
+ sc->vptr->list_length (sc,
+ sc->vptr->pair_car (v_element)) == 3))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a color "
+ "(argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ color_list = sc->vptr->pair_car (v_element);
+ r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ color_list = sc->vptr->pair_cdr (color_list);
+ g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ color_list = sc->vptr->pair_cdr (color_list);
+ b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+
+ gimp_rgba_set_uchar (&args[i].data.d_colorarray[j],
+ r, g, b, 255);
+ }
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" color vector has %ld elements\n", count);
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_PARASITE:
+ if (!sc->vptr->is_list (sc, sc->vptr->pair_car (a)) ||
+ sc->vptr->list_length (sc, sc->vptr->pair_car (a)) != 3)
+ success = FALSE;
+ if (success)
+ {
+ pointer temp_val;
+
+ /* parasite->name */
+ temp_val = sc->vptr->pair_car (a);
+
+ if (!sc->vptr->is_string (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.name =
+ sc->vptr->string_value (sc->vptr->pair_car (temp_val));
+#if DEBUG_MARSHALL
+ g_printerr (" name '%s'\n", args[i].data.d_parasite.name);
+#endif
+
+ /* parasite->flags */
+ temp_val = sc->vptr->pair_cdr (temp_val);
+
+ if (!sc->vptr->is_number (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.flags =
+ sc->vptr->ivalue (sc->vptr->pair_car (temp_val));
+#if DEBUG_MARSHALL
+ g_printerr (" flags %d", args[i].data.d_parasite.flags);
+#endif
+
+ /* parasite->data */
+ temp_val = sc->vptr->pair_cdr (temp_val);
+
+ if (!sc->vptr->is_string (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.data =
+ sc->vptr->string_value (sc->vptr->pair_car (temp_val));
+ args[i].data.d_parasite.size = strlen (args[i].data.d_parasite.data);
+
+#if DEBUG_MARSHALL
+ g_printerr (", size %d\n", args[i].data.d_parasite.size);
+ g_printerr (" data '%s'\n", (char *)args[i].data.d_parasite.data);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STATUS:
+ return foreign_error (sc,
+ "Status is for return types, not arguments",
+ sc->vptr->pair_car (a));
+ break;
+
+ default:
+ g_snprintf (error_str, sizeof (error_str),
+ "Argument %d for %s is an unknown type",
+ i+1, proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Break out of loop before i gets updated when error was detected */
+ if (! success)
+ break;
+ }
+
+ if (success)
+ {
+ /* refuse to refresh scripts from a script, better than crashing
+ * see bug #575830
+ */
+ if (strcmp (proc_name, "script-fu-refresh-scripts"))
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" calling %s...", proc_name);
+#endif
+ values = gimp_run_procedure2 (proc_name, &nvalues, nparams, args);
+#if DEBUG_MARSHALL
+ g_printerr (" done.\n");
+#endif
+ }
+ }
+ else
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Invalid type for argument %d\n", i+1);
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid type for argument %d to %s",
+ i+1, proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Check the return status */
+ if (! values)
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Did not return status\n");
+#endif
+ g_snprintf (error_str, sizeof(error_str),
+ "Procedure execution of %s did not return a status",
+ proc_name);
+
+ return foreign_error (sc, error_str, 0);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *status_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_STATUS_TYPE,
+ values[0].data.d_status,
+ &status_name, NULL, NULL, NULL);
+ g_printerr (" return value is %s\n", status_name);
+ }
+#endif
+
+ switch (values[0].data.d_status)
+ {
+ case GIMP_PDB_EXECUTION_ERROR:
+ if (nvalues > 1 && values[1].type == GIMP_PDB_STRING)
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed: %s",
+ proc_name, values[1].data.d_string);
+ }
+ else
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed",
+ proc_name);
+ }
+ return foreign_error (sc, error_str, 0);
+ break;
+
+ case GIMP_PDB_CALLING_ERROR:
+ if (nvalues > 1 && values[1].type == GIMP_PDB_STRING)
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed on invalid input arguments: %s",
+ proc_name, values[1].data.d_string);
+ }
+ else
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed on invalid input arguments",
+ proc_name);
+ }
+ return foreign_error (sc, error_str, 0);
+ break;
+
+ case GIMP_PDB_SUCCESS:
+#if DEBUG_MARSHALL
+ g_printerr (" values returned: %d\n", nvalues-1);
+#endif
+ for (i = nvalues - 2; i >= 0; --i)
+ {
+ const gchar *string;
+ gint j;
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *type_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE,
+ return_vals[i].type,
+ &type_name, NULL, NULL, NULL);
+
+ g_printerr (" value %d is type %s (%d)\n",
+ i, type_name, return_vals[i].type);
+ }
+#endif
+ switch (return_vals[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int32),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT16:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int16),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT8:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int8),
+ return_val);
+ break;
+
+ case GIMP_PDB_FLOAT:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_real (sc,
+ values[i + 1].data.d_float),
+ return_val);
+ break;
+
+ case GIMP_PDB_STRING:
+ string = values[i + 1].data.d_string;
+ if (! string)
+ string = "";
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc, string),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ {
+ gint32 num_int32s = values[i].data.d_int32;
+ gint32 *array = (gint32 *) values[i + 1].data.d_int32array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int32s);
+
+ for (j = 0; j < num_int32s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ {
+ gint32 num_int16s = values[i].data.d_int32;
+ gint16 *array = (gint16 *) values[i + 1].data.d_int16array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int16s);
+
+ for (j = 0; j < num_int16s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ {
+ gint32 num_int8s = values[i].data.d_int32;
+ guint8 *array = (guint8 *) values[i + 1].data.d_int8array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int8s);
+
+ for (j = 0; j < num_int8s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ {
+ gint32 num_floats = values[i].data.d_int32;
+ gdouble *array = (gdouble *) values[i + 1].data.d_floatarray;
+ pointer vector = sc->vptr->mk_vector (sc, num_floats);
+
+ for (j = 0; j < num_floats; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_real (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ {
+ gint num_strings = values[i].data.d_int32;
+ gchar **array = (gchar **) values[i + 1].data.d_stringarray;
+ pointer list = sc->NIL;
+
+ for (j = num_strings - 1; j >= 0; j--)
+ {
+ list = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc,
+ array[j] ?
+ array[j] : ""),
+ list);
+ }
+
+ return_val = sc->vptr->cons (sc, list, return_val);
+ }
+ break;
+
+ case GIMP_PDB_COLOR:
+ {
+ guchar r, g, b;
+ gpointer temp_val;
+
+ gimp_rgb_get_uchar (&values[i + 1].data.d_color, &r, &g, &b);
+
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, r),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, g),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, b),
+ sc->NIL)));
+ return_val = sc->vptr->cons (sc,
+ temp_val,
+ return_val);
+ break;
+ }
+
+ case GIMP_PDB_COLORARRAY:
+ {
+ gint32 num_colors = values[i].data.d_int32;
+ GimpRGB *array = (GimpRGB *) values[i + 1].data.d_colorarray;
+ pointer vector = sc->vptr->mk_vector (sc, num_colors);
+
+ for (j = 0; j < num_colors; j++)
+ {
+ guchar r, g, b;
+ pointer temp_val;
+
+ gimp_rgb_get_uchar (&array[j], &r, &g, &b);
+
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, r),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, g),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, b),
+ sc->NIL)));
+ sc->vptr->set_vector_elem (vector, j, temp_val);
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_PARASITE:
+ {
+ if (values[i + 1].data.d_parasite.name == NULL)
+ {
+ return_val = foreign_error (sc, "Error: null parasite", 0);
+ }
+ else
+ {
+ GimpParasite *p = &values[i + 1].data.d_parasite;
+ gchar *data = g_strndup (p->data, p->size);
+ gint char_cnt = g_utf8_strlen (data, p->size);
+ pointer temp_val;
+
+ /* don't move the mk_foo() calls outside this function call,
+ * otherwise they might be garbage collected away!
+ */
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc, p->name),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, p->flags),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_counted_string (sc,
+ data,
+ char_cnt),
+ sc->NIL)));
+ return_val = sc->vptr->cons (sc,
+ temp_val,
+ return_val);
+ g_free (data);
+
+#if DEBUG_MARSHALL
+ g_printerr (" name '%s'\n", p->name);
+ g_printerr (" flags %d", p->flags);
+ g_printerr (", size %d\n", p->size);
+ g_printerr (" data '%.*s'\n",
+ p->size, (gchar *) p->data);
+#endif
+ }
+ }
+ break;
+
+ case GIMP_PDB_STATUS:
+ return foreign_error (sc, "Procedure execution returned multiple status values", 0);
+ break;
+
+ default:
+ return foreign_error (sc, "Unknown return type", 0);
+ }
+ }
+
+ case GIMP_PDB_PASS_THROUGH:
+ case GIMP_PDB_CANCEL: /* should we do something here? */
+ break;
+ }
+
+ /* If we have no return value(s) from PDB call, return
+ * either TRUE or FALSE to indicate if call succeeded.
+ */
+ if (return_val == sc->NIL)
+ {
+ if (values[0].data.d_status == GIMP_PDB_SUCCESS)
+ return_val = sc->vptr->cons (sc, sc->T, sc->NIL);
+ else
+ return_val = sc->vptr->cons (sc, sc->F, sc->NIL);
+ }
+
+ /* free the proc name */
+ g_free (proc_name);
+
+ /* free up the executed procedure return values */
+ gimp_destroy_params (values, nvalues);
+
+ /* free up arguments and values */
+ script_fu_marshal_destroy_args (args, nparams);
+
+ /* free the query information */
+ g_free (proc_blurb);
+ g_free (proc_help);
+ g_free (proc_author);
+ g_free (proc_copyright);
+ g_free (proc_date);
+ g_free (params);
+ g_free (return_vals);
+
+ /* if we're in server mode, listen for additional commands for 10 ms */
+ if (script_fu_server_get_mode ())
+ script_fu_server_listen (10);
+
+#ifdef GDK_WINDOWING_WIN32
+ /* This seems to help a lot on Windoze. */
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+#endif
+
+ return return_val;
+}
+
+static pointer
+script_fu_marshal_procedure_call_strict (scheme *sc,
+ pointer a)
+{
+ return script_fu_marshal_procedure_call (sc, a, FALSE);
+}
+
+static pointer
+script_fu_marshal_procedure_call_permissive (scheme *sc,
+ pointer a)
+{
+ return script_fu_marshal_procedure_call (sc, a, TRUE);
+}
+
+static void
+script_fu_marshal_destroy_args (GimpParam *params,
+ gint n_params)
+{
+ gint i;
+
+ for (i = 0; i < n_params; i++)
+ {
+ switch (params[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_INT16:
+ case GIMP_PDB_INT8:
+ case GIMP_PDB_FLOAT:
+ case GIMP_PDB_STRING:
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ g_free (params[i].data.d_int32array);
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ g_free (params[i].data.d_int16array);
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ g_free (params[i].data.d_int8array);
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ g_free (params[i].data.d_floatarray);
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ g_free (params[i].data.d_stringarray);
+ break;
+
+ case GIMP_PDB_COLORARRAY:
+ g_free (params[i].data.d_colorarray);
+ break;
+
+ case GIMP_PDB_COLOR:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ case GIMP_PDB_PARASITE:
+ case GIMP_PDB_STATUS:
+ case GIMP_PDB_END:
+ break;
+ }
+ }
+
+ g_free (params);
+}
+
+static pointer
+script_fu_register_call (scheme *sc,
+ pointer a)
+{
+ return script_fu_add_script (sc, a);
+}
+
+static pointer
+script_fu_menu_register_call (scheme *sc,
+ pointer a)
+{
+ return script_fu_add_menu (sc, a);
+}
+
+static pointer
+script_fu_quit_call (scheme *sc,
+ pointer a)
+{
+ script_fu_server_quit ();
+
+ scheme_deinit (sc);
+
+ return sc->NIL;
+}
+
+static pointer
+script_fu_nil_call (scheme *sc,
+ pointer a)
+{
+ return sc->NIL;
+}