[gimp-tiny-fu] Merge of Script-Fu from git master of GIMP as of commit 262cc1c9



commit 35d90c2a93ebefc25c64ef0b2329477115526f21
Author: Kevin Cozens <kcozens svn gnome org>
Date:   Tue Nov 22 21:32:31 2011 -0500

    Merge of Script-Fu from git master of GIMP as of commit 262cc1c9
    
    This is not working yet but it is getting closer. TinyScheme is invoked for
    each Scheme (.scm) script in the plug-ins directory. Tiny-Fu is loaded as a
    Scheme extension and some menu items are registered. The Tiny-Fu code still
    needs some work before it will properly run scripts.

 Makefile.am                    |    1 -
 TODO                           |    2 +-
 autogen.sh                     |   15 +-
 configure.in                   |    1 -
 po/Makefile.in.in              |  257 +------
 re/COPYRIGHT                   |   20 -
 re/Makefile.am                 |   57 --
 re/README                      |   32 -
 re/README.1st                  |   27 -
 re/WHATSNEW                    |   92 ---
 re/cclass.h                    |   31 -
 re/cname.h                     |  102 ---
 re/debug.c                     |  236 ------
 re/debug.ih                    |   14 -
 re/engine.c                    | 1019 --------------------------
 re/engine.ih                   |   35 -
 re/main.c                      |  508 -------------
 re/main.ih                     |   19 -
 re/mkh                         |   76 --
 re/re.c                        |  112 ---
 re/re.h                        |    2 -
 re/re.makefile                 |   46 --
 re/re.scm                      |   15 -
 re/regcomp.c                   | 1540 ----------------------------------------
 re/regcomp.ih                  |   48 --
 re/regerror.c                  |  118 ---
 re/regerror.ih                 |   12 -
 re/regex.001                   |  106 ---
 re/regex.3                     |  502 -------------
 re/regex.7                     |  233 ------
 re/regex.h                     |   88 ---
 re/regex2.h                    |  138 ----
 re/regexec.c                   |  134 ----
 re/regfree.c                   |   34 -
 re/split.c                     |  318 ---------
 re/split.h                     |    7 -
 re/tests                       |  475 -------------
 re/utils.h                     |   22 -
 scripts/Makefile.am            |    3 +-
 scripts/script-fu.init         |    8 -
 scripts/test-sphere.scm        |    2 +-
 scripts/ts-helloworld.scm      |    2 +-
 tiny-fu/Makefile.am            |   18 +-
 tiny-fu/scheme-wrapper.c       | 1274 +++++++++++++++++----------------
 tiny-fu/scheme-wrapper.h       |   51 +-
 tiny-fu/tiny-fu-console.c      |  123 ++--
 tiny-fu/tiny-fu-console.h      |   24 +-
 tiny-fu/tiny-fu-enums.h        |    7 +-
 tiny-fu/tiny-fu-eval.c         |   80 +++
 tiny-fu/tiny-fu-eval.h         |   29 +
 tiny-fu/tiny-fu-interface.c    |  687 ++++++++----------
 tiny-fu/tiny-fu-interface.h    |   15 +-
 tiny-fu/tiny-fu-intl.h         |   29 +-
 tiny-fu/tiny-fu-regex.c        |  170 +++++
 tiny-fu/tiny-fu-regex.h        |   25 +
 tiny-fu/tiny-fu-script.c       |  780 ++++++++++++++++++++
 tiny-fu/tiny-fu-script.h       |   49 ++
 tiny-fu/tiny-fu-scripts.c      | 1471 +++++++++++++-------------------------
 tiny-fu/tiny-fu-scripts.h      |   18 +-
 tiny-fu/tiny-fu-server.c       |  197 +++--
 tiny-fu/tiny-fu-server.h       |    7 +-
 tiny-fu/tiny-fu-text-console.c |   15 +-
 tiny-fu/tiny-fu-text-console.h |   19 +-
 tiny-fu/tiny-fu-types.h        |   46 +-
 tiny-fu/tiny-fu-utils.c        |   69 ++
 tiny-fu/tiny-fu-utils.h        |   25 +
 tiny-fu/tiny-fu.c              |  160 ++---
 tinyscheme/scheme.c            |   60 +-
 68 files changed, 3105 insertions(+), 8852 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index ee61102..89dbbea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,6 @@
 SUBDIRS = \
        po         \
        ftx        \
-       re         \
        tinyscheme \
        tiny-fu    \
        scripts
diff --git a/TODO b/TODO
index 0e4c104..dcaafda 100644
--- a/TODO
+++ b/TODO
@@ -11,7 +11,7 @@ NOTES for Tiny-Fu version 2:
 - Should Makefile's be using PLATFORM_WIN32 or OS_WIN32?
 
 Command line parameters:
-       script_name -gimp read_fd write_fd -query 1
+       /full/path/to/script_name -gimp read_fd write_fd -query 1
 
 The last parameter is the stack trace mode. The values are:
 0 - Never
diff --git a/autogen.sh b/autogen.sh
index cdc7cbe..21aba71 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -14,14 +14,14 @@ PROJECT="GIMP Tiny-Fu"
 TEST_TYPE=-f
 FILE=tiny-fu/tiny-fu.c
 
-ACLOCAL=${ACLOCAL-aclocal-1.9}
+ACLOCAL=${ACLOCAL-aclocal-1.11}
 AUTOCONF=${AUTOCONF-autoconf}
 AUTOHEADER=${AUTOHEADER-autoheader}
-AUTOMAKE=${AUTOMAKE-automake-1.9}
+AUTOMAKE=${AUTOMAKE-automake-1.11}
 LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
 
 AUTOCONF_REQUIRED_VERSION=2.54
-AUTOMAKE_REQUIRED_VERSION=1.8.3
+AUTOMAKE_REQUIRED_VERSION=1.10.0
 GLIB_REQUIRED_VERSION=2.2.0
 INTLTOOL_REQUIRED_VERSION=0.31
 LIBTOOL_REQUIRED_VERSION=1.4
@@ -131,15 +131,12 @@ echo -n "checking for automake >= $AUTOMAKE_REQUIRED_VERSION ... "
 if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1; then
    AUTOMAKE=$AUTOMAKE
    ACLOCAL=$ACLOCAL
+elif (automake-1.11 --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake-1.11
+   ACLOCAL=aclocal-1.11
 elif (automake-1.10 --version) < /dev/null > /dev/null 2>&1; then
    AUTOMAKE=automake-1.10
    ACLOCAL=aclocal-1.10
-elif (automake-1.9 --version) < /dev/null > /dev/null 2>&1; then
-   AUTOMAKE=automake-1.9
-   ACLOCAL=aclocal-1.9
-elif (automake-1.8 --version) < /dev/null > /dev/null 2>&1; then
-   AUTOMAKE=automake-1.8
-   ACLOCAL=aclocal-1.8
 else
     echo
     echo "  You must have automake $AUTOMAKE_REQUIRED_VERSION or newer installed to compile $PROJECT."
diff --git a/configure.in b/configure.in
index 85bc664..a102539 100644
--- a/configure.in
+++ b/configure.in
@@ -309,7 +309,6 @@ AC_SUBST(GIMP_LOCALEDIR)
 AC_CONFIG_FILES([
 Makefile
 ftx/Makefile
-re/Makefile
 tinyscheme/Makefile
 tiny-fu/Makefile
 scripts/Makefile
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
deleted file mode 100644
index 22cadc6..0000000
--- a/po/Makefile.in.in
+++ /dev/null
@@ -1,256 +0,0 @@
-# Makefile for program source directory in GNU NLS utilities package.
-# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper gnu ai mit edu>
-#
-# This file file be copied and used freely without restrictions.  It can
-# be used in projects which are not available under the GNU Public License
-# but which still want to provide support for the GNU gettext functionality.
-# Please note that the actual code is *not* freely available.
-#
-# - Modified by Owen Taylor <otaylor redhat com> to use GETTEXT_PACKAGE
-#   instead of PACKAGE and to look for po2tbl in ./ not in intl/
-#
-# - Modified by jacob berkman <jacob ximian com> to install
-#   Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
-
-GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
-PACKAGE = @PACKAGE@
-VERSION = @VERSION@
-
-SHELL = /bin/sh
-@SET_MAKE@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-top_builddir = ..
-VPATH = @srcdir@
-
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-datadir = @datadir@
-libdir = @libdir@
-localedir = $(libdir)/locale
-gnulocaledir = $(datadir)/locale
-gettextsrcdir = $(datadir)/glib-2.0/gettext/po
-subdir = po
-install_sh = @install_sh@
-mkdir_p = @mkdir_p@
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-
-CC = @CC@
-GENCAT = @GENCAT@
-GMSGFMT = @GMSGFMT@
-MSGFMT = @MSGFMT@
-XGETTEXT = @XGETTEXT@
-INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
-INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
-MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package 
$(GETTEXT_PACKAGE) --dist
-GENPOT   = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package 
$(GETTEXT_PACKAGE) --pot
-
-DEFS = @DEFS@
-CFLAGS = @CFLAGS@
-CPPFLAGS = @CPPFLAGS@
-
-INCLUDES = -I.. -I$(top_srcdir)/intl
-
-COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
-
-SOURCES = 
-POFILES = @POFILES@
-GMOFILES = @GMOFILES@
-DISTFILES = ChangeLog Makefile.in.in POTFILES.in \
-$(POFILES) $(GMOFILES) $(SOURCES)
-
-POTFILES = \
-
-CATALOGS = @CATALOGS@
-CATOBJEXT = @CATOBJEXT@
-INSTOBJEXT = @INSTOBJEXT@
-
-.SUFFIXES:
-.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
-
-.c.o:
-       $(COMPILE) $<
-
-.po.pox:
-       $(MAKE) $(GETTEXT_PACKAGE).pot
-       $(MSGMERGE) $< $(top_builddir)/po/$(GETTEXT_PACKAGE).pot -o $*pox
-
-.po.mo:
-       $(MSGFMT) -o $@ $<
-
-.po.gmo:
-       file=`echo $* | sed 's,.*/,,'`.gmo \
-         && rm -f $$file && $(GMSGFMT) -o $$file $<
-
-.po.cat:
-       sed -f ../intl/po2msg.sed < $< > $*.msg \
-         && rm -f $@ && $(GENCAT) $@ $*.msg
-
-
-all: all-@USE_NLS@
-
-all-yes: $(CATALOGS)
-all-no:
-
-$(GETTEXT_PACKAGE).pot: $(POTFILES)
-       $(GENPOT)
-
-install: install-exec install-data
-install-exec:
-install-data: install-data-@USE_NLS@
-install-data-no: all
-install-data-yes: all
-       if test -n "$(MKINSTALLDIRS)"; then \
-         $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \
-       else \
-         $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir); \
-       fi
-       @catalogs='$(CATALOGS)'; \
-       for cat in $$catalogs; do \
-         cat=`basename $$cat`; \
-         case "$$cat" in \
-           *.gmo) destdir=$(gnulocaledir);; \
-           *)     destdir=$(localedir);; \
-         esac; \
-         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
-         dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \
-         if test -n "$(MKINSTALLDIRS)"; then \
-           $(MKINSTALLDIRS) $$dir; \
-         else \
-           $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
-         fi; \
-         if test -r $$cat; then \
-           $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
-           echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
-         else \
-           $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
-           echo "installing $(srcdir)/$$cat as" \
-                "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \
-         fi; \
-         if test -r $$cat.m; then \
-           $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
-           echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
-         else \
-           if test -r $(srcdir)/$$cat.m ; then \
-             $(INSTALL_DATA) $(srcdir)/$$cat.m \
-               $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
-             echo "installing $(srcdir)/$$cat as" \
-                  "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \
-           else \
-             true; \
-           fi; \
-         fi; \
-       done
-       if test "$(PACKAGE)" = "glib"; then \
-         if test -n "$(MKINSTALLDIRS)"; then \
-           $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \
-         else \
-           $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(gettextsrcdir); \
-         fi; \
-         $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
-                         $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
-       else \
-         : ; \
-       fi
-
-# Define this as empty until I found a useful application.
-installcheck:
-
-uninstall:
-       catalogs='$(CATALOGS)'; \
-       for cat in $$catalogs; do \
-         cat=`basename $$cat`; \
-         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
-         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
-         rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
-         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \
-         rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \
-       done
-       if test "$(PACKAGE)" = "glib"; then \
-         rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
-       fi
-
-check: all
-
-dvi info tags TAGS ID:
-
-mostlyclean:
-       rm -f core core.* *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp
-       rm -fr *.o
-       rm -f .intltool-merge-cache
-
-clean: mostlyclean
-
-distclean: clean
-       rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
-
-maintainer-clean: distclean
-       @echo "This command is intended for maintainers to use;"
-       @echo "it deletes files that may require special tools to rebuild."
-       rm -f $(GMOFILES)
-
-distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir)
-dist distdir: $(DISTFILES) $(GETTEXT_PACKAGE).pot
-       dists="$(DISTFILES)"; \
-       for file in $$dists; do \
-         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
-           || cp -p $(srcdir)/$$file $(distdir); \
-       done
-
-update-po: Makefile
-       $(MAKE) $(GETTEXT_PACKAGE).pot
-       tmpdir=`pwd`; \
-       catalogs='$(CATALOGS)'; \
-       for cat in $$catalogs; do \
-         cat=`basename $$cat`; \
-         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
-         echo "$$lang:"; \
-         result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \
-         if $$result; then \
-           if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
-             rm -f $$tmpdir/$$lang.new.po; \
-            else \
-             if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
-               :; \
-             else \
-               echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
-               rm -f $$tmpdir/$$lang.new.po; \
-               exit 1; \
-             fi; \
-           fi; \
-         else \
-           echo "msgmerge for $$cat failed!"; \
-           rm -f $$tmpdir/$$lang.new.po; \
-         fi; \
-       done
-
-# POTFILES is created from POTFILES.in by stripping comments, empty lines
-# and Intltool tags (enclosed in square brackets), and appending a full
-# relative path to them
-POTFILES: POTFILES.in
-       ( if test 'x$(srcdir)' != 'x.'; then \
-           posrcprefix='$(top_srcdir)/'; \
-         else \
-           posrcprefix="../"; \
-         fi; \
-         rm -f $@-t $@ \
-           && (sed -e '/^#/d'                                          \
-                   -e "s/^\[.*\] +//"                                  \
-                   -e '/^[     ]*$$/d'                                 \
-                   -e "s@.*@   $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
-               | sed -e '$$s/\\$$//') > $@-t \
-           && chmod a-w $@-t \
-           && mv $@-t $@ )
-
-Makefile: Makefile.in.in ../config.status POTFILES
-       cd .. \
-         && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
-              $(SHELL) ./config.status
-
-# Tell versions [3.59,3.63) of GNU make not to export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 120000
index 0000000..e4713cf
--- /dev/null
+++ b/po/Makefile.in.in
@@ -0,0 +1 @@
+/usr/share/intltool/Makefile.in.in
\ No newline at end of file
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 7f288e4..e171219 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -8,7 +8,8 @@ scriptsdir = $(GIMP_PLUGINDIR)
 
 initscripts = \
        script-fu.init                  \
-       script-fu-compat.init
+       script-fu-compat.init           \
+       plug-in-compat.init
 
 scripts = \
        3d-outline.scm                  \
diff --git a/scripts/script-fu.init b/scripts/script-fu.init
index 7a84b9f..120ecc7 100644
--- a/scripts/script-fu.init
+++ b/scripts/script-fu.init
@@ -711,11 +711,3 @@
             (else (error "cond-expand : unknown operator" (car condition)))))))
 
 (gc-verbose #f)
-
-(load "script-fu-compat.init")
-(load-extension "tiny_fu")
-
-;There is no function available in the TinyScheme API to access *args*
-;to allow full initialization to be done when the extension is loaded
-;so call the main init routine and pass the command line arguments.
-(tiny-fu-init *args*)
diff --git a/scripts/test-sphere.scm b/scripts/test-sphere.scm
index 2b4cbe1..7d6a67a 100644
--- a/scripts/test-sphere.scm
+++ b/scripts/test-sphere.scm
@@ -299,4 +299,4 @@
 )
 
 (script-fu-menu-register "script-fu-test-sphere"
-                         "<Image>/Filters/Languages/Script-Fu/Test")
+                         "<Image>/Filters/Languages/Tiny-Fu/Test")
diff --git a/scripts/ts-helloworld.scm b/scripts/ts-helloworld.scm
index 90fd92e..47af77d 100644
--- a/scripts/ts-helloworld.scm
+++ b/scripts/ts-helloworld.scm
@@ -62,4 +62,4 @@
 )
 
 (script-fu-menu-register "script-fu-helloworld"
-                         "<Image>/Filters/Languages/Script-Fu/Test")
+                         "<Image>/Filters/Languages/Tiny-Fu/Test")
diff --git a/tiny-fu/Makefile.am b/tiny-fu/Makefile.am
index 00c2dd3..7ebc82b 100644
--- a/tiny-fu/Makefile.am
+++ b/tiny-fu/Makefile.am
@@ -17,20 +17,28 @@ tiny_fu_ladir = $(GIMP_LIBDIR)/tiny-fu
 tiny_fu_la_LTLIBRARIES = tiny_fu.la
 
 tiny_fu_la_SOURCES = \
-    tiny-fu-types.h        \
-    tiny-fu-enums.h        \
+    tiny-fu.c              \
     tiny-fu-console.c      \
     tiny-fu-console.h      \
+    tiny-fu-enums.h        \
+    tiny-fu-eval.c         \
+    tiny-fu-eval.h         \
     tiny-fu-interface.c    \
     tiny-fu-interface.h    \
-    tiny-fu-text-console.h \
-    tiny-fu-text-console.c \
     tiny-fu-intl.h         \
+    tiny-fu-regex.c        \
+    tiny-fu-regex.h        \
+    tiny-fu-script.c       \
+    tiny-fu-script.h       \
     tiny-fu-scripts.c      \
     tiny-fu-scripts.h      \
     tiny-fu-server.c       \
     tiny-fu-server.h       \
-    tiny-fu.c              \
+    tiny-fu-text-console.c \
+    tiny-fu-text-console.h \
+    tiny-fu-types.h        \
+    tiny-fu-utils.c        \
+    tiny-fu-utils.h        \
     scheme-wrapper.c       \
     scheme-wrapper.h
 
diff --git a/tiny-fu/scheme-wrapper.c b/tiny-fu/scheme-wrapper.c
index b16301f..c6112ee 100644
--- a/tiny-fu/scheme-wrapper.c
+++ b/tiny-fu/scheme-wrapper.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,18 +12,17 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #if 0
-#define DEBUG_MARSHALL       0  /* No need to define this until you need it */
-#define DEBUG_SCRIPTS        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> /* memcpy, strcpy, strlen */
+#include <string.h>
 
 #include <glib/gstdio.h>
 
@@ -36,26 +35,48 @@
 #include "tinyscheme/dynload.h"
 #endif
 #include "ftx/ftx.h"
-#include "re/re.h"
 
 #include "tiny-fu-types.h"
 
 #include "tiny-fu-console.h"
 #include "tiny-fu-interface.h"
+#include "tiny-fu-regex.h"
 #include "tiny-fu-scripts.h"
 #include "tiny-fu-server.h"
 
 #include "scheme-wrapper.h"
 
+
 #undef cons
 
-struct named_constant
+static void     ts_init_constants                (scheme    *sc);
+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);
+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;
 
-struct named_constant const script_constants[] =
+static const NamedConstant const script_constants[] =
 {
   /* Useful values from libgimpbase/gimplimits.h */
   { "MIN-IMAGE-SIZE", GIMP_MIN_IMAGE_SIZE },
@@ -104,64 +125,65 @@ struct named_constant const script_constants[] =
   { NULL, 0 }
 };
 
-/* The following constants are deprecated. They are */
-/* included to keep backwards compatability with    */
-/* older scripts used with version 2.0 of GIMP.     */
-struct named_constant const old_constants[] =
+/* The following constants are deprecated. They are
+ * included to keep backwards compatability with
+ * older scripts used with version 2.0 of GIMP.
+ */
+static const NamedConstant const old_constants[] =
 {
-  { "NORMAL",       GIMP_NORMAL_MODE       },
-  { "DISSOLVE",     GIMP_DISSOLVE_MODE     },
-  { "BEHIND",       GIMP_BEHIND_MODE       },
-  { "MULTIPLY",     GIMP_MULTIPLY_MODE     },
-  { "SCREEN",       GIMP_SCREEN_MODE       },
-  { "OVERLAY",      GIMP_OVERLAY_MODE      },
-  { "DIFFERENCE",   GIMP_DIFFERENCE_MODE   },
-  { "ADDITION",     GIMP_ADDITION_MODE     },
-  { "SUBTRACT",     GIMP_SUBTRACT_MODE     },
-  { "DARKEN-ONLY",  GIMP_DARKEN_ONLY_MODE  },
-  { "LIGHTEN-ONLY", GIMP_LIGHTEN_ONLY_MODE },
-  { "HUE",          GIMP_HUE_MODE          },
-  { "SATURATION",   GIMP_SATURATION_MODE   },
-  { "COLOR",        GIMP_COLOR_MODE        },
-  { "VALUE",        GIMP_VALUE_MODE        },
-  { "DIVIDE",       GIMP_DIVIDE_MODE       },
-
-  { "BLUR",         GIMP_BLUR_CONVOLVE     },
-  { "SHARPEN",      GIMP_SHARPEN_CONVOLVE  },
-
-  { "WHITE-MASK",     GIMP_ADD_WHITE_MASK     },
-  { "BLACK-MASK",     GIMP_ADD_BLACK_MASK     },
-  { "ALPHA-MASK",     GIMP_ADD_ALPHA_MASK     },
-  { "SELECTION-MASK", GIMP_ADD_SELECTION_MASK },
-  { "COPY-MASK",      GIMP_ADD_COPY_MASK      },
-
-  { "ADD",          GIMP_CHANNEL_OP_ADD       },
-  { "SUB",          GIMP_CHANNEL_OP_SUBTRACT  },
-  { "REPLACE",      GIMP_CHANNEL_OP_REPLACE   },
-  { "INTERSECT",    GIMP_CHANNEL_OP_INTERSECT },
-
-  { "FG-BG-RGB",    GIMP_FG_BG_RGB_MODE       },
-  { "FG-BG-HSV",    GIMP_FG_BG_HSV_MODE       },
-  { "FG-TRANS",     GIMP_FG_TRANSPARENT_MODE  },
-  { "CUSTOM",       GIMP_CUSTOM_MODE          },
-
-  { "FG-IMAGE-FILL",    GIMP_FOREGROUND_FILL  },
-  { "BG-IMAGE-FILL",    GIMP_BACKGROUND_FILL  },
-  { "WHITE-IMAGE-FILL", GIMP_WHITE_FILL       },
-  { "TRANS-IMAGE-FILL", GIMP_TRANSPARENT_FILL },
-
-  { "APPLY",        GIMP_MASK_APPLY   },
-  { "DISCARD",      GIMP_MASK_DISCARD },
-
-  { "HARD",         GIMP_BRUSH_HARD },
-  { "SOFT",         GIMP_BRUSH_SOFT },
-
-  { "CONTINUOUS",   GIMP_PAINT_CONSTANT    },
-  { "INCREMENTAL",  GIMP_PAINT_INCREMENTAL },
-
-  { "HORIZONTAL",   GIMP_ORIENTATION_HORIZONTAL },
-  { "VERTICAL",     GIMP_ORIENTATION_VERTICAL   },
-  { "UNKNOWN",      GIMP_ORIENTATION_UNKNOWN    },
+  { "NORMAL",               GIMP_NORMAL_MODE       },
+  { "DISSOLVE",             GIMP_DISSOLVE_MODE     },
+  { "BEHIND",               GIMP_BEHIND_MODE       },
+  { "MULTIPLY",             GIMP_MULTIPLY_MODE     },
+  { "SCREEN",               GIMP_SCREEN_MODE       },
+  { "OVERLAY",              GIMP_OVERLAY_MODE      },
+  { "DIFFERENCE",           GIMP_DIFFERENCE_MODE   },
+  { "ADDITION",             GIMP_ADDITION_MODE     },
+  { "SUBTRACT",             GIMP_SUBTRACT_MODE     },
+  { "DARKEN-ONLY",          GIMP_DARKEN_ONLY_MODE  },
+  { "LIGHTEN-ONLY",         GIMP_LIGHTEN_ONLY_MODE },
+  { "HUE",                  GIMP_HUE_MODE          },
+  { "SATURATION",           GIMP_SATURATION_MODE   },
+  { "COLOR",                GIMP_COLOR_MODE        },
+  { "VALUE",                GIMP_VALUE_MODE        },
+  { "DIVIDE",               GIMP_DIVIDE_MODE       },
+
+  { "BLUR",                 GIMP_BLUR_CONVOLVE     },
+  { "SHARPEN",              GIMP_SHARPEN_CONVOLVE  },
+
+  { "WHITE-MASK",           GIMP_ADD_WHITE_MASK     },
+  { "BLACK-MASK",           GIMP_ADD_BLACK_MASK     },
+  { "ALPHA-MASK",           GIMP_ADD_ALPHA_MASK     },
+  { "SELECTION-MASK",       GIMP_ADD_SELECTION_MASK },
+  { "COPY-MASK",            GIMP_ADD_COPY_MASK      },
+
+  { "ADD",                  GIMP_CHANNEL_OP_ADD       },
+  { "SUB",                  GIMP_CHANNEL_OP_SUBTRACT  },
+  { "REPLACE",              GIMP_CHANNEL_OP_REPLACE   },
+  { "INTERSECT",            GIMP_CHANNEL_OP_INTERSECT },
+
+  { "FG-BG-RGB",            GIMP_FG_BG_RGB_MODE       },
+  { "FG-BG-HSV",            GIMP_FG_BG_HSV_MODE       },
+  { "FG-TRANS",             GIMP_FG_TRANSPARENT_MODE  },
+  { "CUSTOM",               GIMP_CUSTOM_MODE          },
+
+  { "FG-IMAGE-FILL",        GIMP_FOREGROUND_FILL  },
+  { "BG-IMAGE-FILL",        GIMP_BACKGROUND_FILL  },
+  { "WHITE-IMAGE-FILL",     GIMP_WHITE_FILL       },
+  { "TRANS-IMAGE-FILL",     GIMP_TRANSPARENT_FILL },
+
+  { "APPLY",                GIMP_MASK_APPLY   },
+  { "DISCARD",              GIMP_MASK_DISCARD },
+
+  { "HARD",                 GIMP_BRUSH_HARD },
+  { "SOFT",                 GIMP_BRUSH_SOFT },
+
+  { "CONTINUOUS",           GIMP_PAINT_CONSTANT    },
+  { "INCREMENTAL",          GIMP_PAINT_INCREMENTAL },
+
+  { "HORIZONTAL",           GIMP_ORIENTATION_HORIZONTAL },
+  { "VERTICAL",             GIMP_ORIENTATION_VERTICAL   },
+  { "UNKNOWN",              GIMP_ORIENTATION_UNKNOWN    },
 
   { "LINEAR",               GIMP_GRADIENT_LINEAR               },
   { "BILINEAR",             GIMP_GRADIENT_BILINEAR             },
@@ -175,11 +197,11 @@ struct named_constant const old_constants[] =
   { "SPIRAL-CLOCKWISE",     GIMP_GRADIENT_SPIRAL_CLOCKWISE     },
   { "SPIRAL-ANTICLOCKWISE", GIMP_GRADIENT_SPIRAL_ANTICLOCKWISE },
 
-  { "VALUE-LUT",      GIMP_HISTOGRAM_VALUE },
-  { "RED-LUT",        GIMP_HISTOGRAM_RED   },
-  { "GREEN-LUT",      GIMP_HISTOGRAM_GREEN },
-  { "BLUE-LUT",       GIMP_HISTOGRAM_BLUE  },
-  { "ALPHA-LUT",      GIMP_HISTOGRAM_ALPHA },
+  { "VALUE-LUT",            GIMP_HISTOGRAM_VALUE },
+  { "RED-LUT",              GIMP_HISTOGRAM_RED   },
+  { "GREEN-LUT",            GIMP_HISTOGRAM_GREEN },
+  { "BLUE-LUT",             GIMP_HISTOGRAM_BLUE  },
+  { "ALPHA-LUT",            GIMP_HISTOGRAM_ALPHA },
 
   { NULL, 0 }
 };
@@ -189,25 +211,70 @@ static scheme sc;
 
 
 void
-ts_stdout_output_func (TsOutputType  type,
-                       const char   *string,
-                       int           len,
-                       gpointer      user_data)
+tinyscheme_init (const gchar *path,
+                 gboolean     register_scripts)
 {
-  if (len < 0)
-    len = strlen (string);
-  fprintf (stdout, "%.*s", len, string);
+  /* 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 *dir_list = gimp_path_parse (path, 16, TRUE, NULL);
+      GList *list;
+
+      for (list = dir_list; list; list = g_list_next (list))
+        {
+          if (ts_load_file (list->data, "tiny-fu.init"))
+            {
+              /*  To improve compatibility with older Tiny-Fu scripts,
+               *  load tiny-fu-compat.init from the same directory.
+               */
+              ts_load_file (list->data, "tiny-fu-compat.init");
+
+              /*  To improve compatibility with older GIMP version,
+               *  load plug-in-compat.init from the same directory.
+               */
+              ts_load_file (list->data, "plug-in-compat.init");
+
+              break;
+            }
+        }
+
+      if (list == NULL)
+        g_printerr ("Unable to read initialization file tiny-fu.init\n");
+
+      gimp_path_free (dir_list);
+    }
 }
 
+/* Create an SF-RUN-MODE constant for use in scripts.
+ * It is set to the run mode state determined by GIMP.
+ */
 void
-ts_gstring_output_func (TsOutputType  type,
-                        const char   *string,
-                        int           len,
-                        gpointer      user_data)
+ts_set_run_mode (GimpRunMode run_mode)
 {
-  GString *gstr = (GString *) user_data;
+  pointer symbol;
 
-  g_string_append_len (gstr, string, len);
+  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
@@ -239,7 +306,7 @@ ts_interpret_string (const gchar *expr)
   sc.tracing = 1;
 #endif
 
-  sc.vptr->load_string (&sc, (char *)expr);
+  sc.vptr->load_string (&sc, (char *) expr);
 
   return sc.retcode;
 }
@@ -247,153 +314,74 @@ ts_interpret_string (const gchar *expr)
 const gchar *
 ts_get_success_msg (void)
 {
-  if (sc.vptr->is_string(sc.value))
-    return sc.vptr->string_value(sc.value);
+  if (sc.vptr->is_string (sc.value))
+    return sc.vptr->string_value (sc.value);
 
   return "Success";
 }
 
-
-static void  init_constants  (void);
-static void  init_procedures (void);
-
-static gboolean register_scripts = FALSE;
-
 void
-tinyscheme_init (const gchar *path,
-                 gboolean     local_register_scripts)
-{
-  register_scripts = local_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);
-  init_re (&sc);
-
-  /* register in the interpreter the gimp functions and types. */
-  init_constants ();
-  init_procedures ();
-
-  if (path)
-    {
-      GList *dir_list = gimp_path_parse (path, 16, TRUE, NULL);
-      GList *list;
-
-      for (list = dir_list; list; list = g_list_next (list))
-        {
-          gchar *filename = g_build_filename (list->data,
-                                              "script-fu.init", NULL);
-          FILE  *fin      = g_fopen (filename, "rb");
-
-          g_free (filename);
-
-          if (fin)
-            {
-              scheme_load_file (&sc, fin);
-              fclose (fin);
-
-              /*  To improve compatibility with older Script-Fu scripts,
-               *  load script-fu-compat.init from the same directory.
-               */
-              filename = g_build_filename (list->data,
-                                           "script-fu-compat.init", NULL);
-              fin = g_fopen (filename, "rb");
-              g_free (filename);
-
-              if (fin)
-                {
-                  scheme_load_file (&sc, fin);
-                  fclose (fin);
-                }
-
-              break;
-            }
-        }
-
-      if (list == NULL)
-        g_printerr ("Unable to read initialization file script-fu.init\n");
-
-      gimp_path_free (dir_list);
-    }
-}
-
-void
-tinyscheme_deinit (void)
+ts_stdout_output_func (TsOutputType  type,
+                       const char   *string,
+                       int           len,
+                       gpointer      user_data)
 {
-  scheme_deinit (&sc);
+  if (len < 0)
+    len = strlen (string);
+  fprintf (stdout, "%.*s", len, string);
+  fflush (stdout);
 }
 
-/* Create an SF-RUN-MODE constant for use in scripts.  */
-/* It is set to the run mode state determined by GIMP. */
 void
-set_run_mode_constant (GimpRunMode run_mode)
+ts_gstring_output_func (TsOutputType  type,
+                        const char   *string,
+                        int           len,
+                        gpointer      user_data)
 {
-  pointer symbol;
+  GString *gstr = (GString *) user_data;
 
-  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);
+  g_string_append_len (gstr, string, len);
 }
 
-static void     convert_string                   (gchar  *str);
-static pointer  script_fu_marshal_procedure_call (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);
 
+/*  private functions  */
 
 /*
  * Below can be found the functions responsible for registering the
  * gimp functions and types against the scheme interpreter.
  */
-
-
 static void
-init_constants (void)
+ts_init_constants (scheme *sc)
 {
   const gchar **enum_type_names;
   gint          n_enum_type_names;
   gint          i;
   pointer       symbol;
 
-  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-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-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-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-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);
+  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);
 
@@ -413,10 +401,10 @@ init_constants (void)
               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);
+              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);
             }
@@ -428,94 +416,94 @@ init_constants (void)
   /* 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);
+      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);
+  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-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-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);
+  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);
 
   for (i = 0; old_constants[i].name != NULL; ++i)
     {
-      symbol = sc.vptr->mk_symbol (&sc, old_constants[i].name);
-      sc.vptr->scheme_define (&sc, sc.global_env, symbol,
-                              sc.vptr->mk_integer (&sc,
-                                                   old_constants[i].value));
-      sc.vptr->setimmutable(symbol);
+      symbol = sc->vptr->mk_symbol (sc, old_constants[i].name);
+      sc->vptr->scheme_define (sc, sc->global_env, symbol,
+                               sc->vptr->mk_integer (sc,
+                                                     old_constants[i].value));
+      sc->vptr->setimmutable (symbol);
     }
 }
 
 static void
-init_procedures (void)
+ts_init_procedures (scheme   *sc,
+                    gboolean  register_scripts)
 {
-  gchar          **proc_list;
-  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;
-  gint             num_procs;
-  gint             i;
-  gchar           *buff;
-  pointer          symbol;
+  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);
+  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,
-                                                    script_fu_register_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,
-                                                    script_fu_menu_register_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);
+  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));
-  sc.vptr->setimmutable(symbol);
+  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));
+  sc->vptr->setimmutable (symbol);
 
   gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*",
                             &num_procs, &proc_list);
@@ -523,6 +511,17 @@ init_procedures (void)
   /*  Register each procedure as a scheme func  */
   for (i = 0; i < num_procs; i++)
     {
+      gchar           *proc_blurb;
+      gchar           *proc_help;
+      gchar           *proc_author;
+      gchar           *proc_copyright;
+      gchar           *proc_date;
+      GimpPDBProcType  proc_type;
+      gint             n_params;
+      gint             n_return_vals;
+      GimpParamDef    *params;
+      GimpParamDef    *return_vals;
+
       /*  lookup the procedure  */
       if (gimp_procedural_db_proc_info (proc_list[i],
                                         &proc_blurb,
@@ -531,39 +530,42 @@ init_procedures (void)
                                         &proc_copyright,
                                         &proc_date,
                                         &proc_type,
-                                        &nparams, &nreturn_vals,
+                                        &n_params, &n_return_vals,
                                         &params, &return_vals))
-      {
-         /* Build a define that will call the foreign function */
-         /* The Scheme statement was suggested by Simon Budig  */
-         if (nparams == 0)
-           {
-             buff = g_strdup_printf (" (define (%s)"
-                                     " (gimp-proc-db-call \"%s\"))",
-                                     proc_list[i], proc_list[i]);
-           }
-         else
-           {
-             buff = g_strdup_printf (" (define %s (lambda x"
-                                     " (apply gimp-proc-db-call (cons \"%s\" x))))",
-                                     proc_list[i], proc_list[i]);
-           }
-
-         /*  Execute the 'define'  */
-         sc.vptr->load_string (&sc, buff);
-
-         g_free (buff);
-
-         /*  free the queried information  */
-         g_free (proc_blurb);
-         g_free (proc_help);
-         g_free (proc_author);
-         g_free (proc_copyright);
-         g_free (proc_date);
-
-         gimp_destroy_paramdefs (params, nparams);
-         gimp_destroy_paramdefs (return_vals, nreturn_vals);
-      }
+        {
+          gchar *buff;
+
+          /* Build a define that will call the foreign function.
+           * The Scheme statement was suggested by Simon Budig.
+           */
+          if (n_params == 0)
+            {
+              buff = g_strdup_printf (" (define (%s)"
+                                      " (gimp-proc-db-call \"%s\"))",
+                                      proc_list[i], proc_list[i]);
+            }
+          else
+            {
+              buff = g_strdup_printf (" (define %s (lambda x"
+                                      " (apply gimp-proc-db-call (cons \"%s\" x))))",
+                                      proc_list[i], proc_list[i]);
+            }
+
+          /*  Execute the 'define'  */
+          sc->vptr->load_string (sc, buff);
+
+          g_free (buff);
+
+          /*  free the queried information  */
+          g_free (proc_blurb);
+          g_free (proc_help);
+          g_free (proc_author);
+          g_free (proc_copyright);
+          g_free (proc_date);
+
+          gimp_destroy_paramdefs (params, n_params);
+          gimp_destroy_paramdefs (return_vals, n_return_vals);
+        }
 
       g_free (proc_list[i]);
     }
@@ -571,6 +573,30 @@ init_procedures (void)
   g_free (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)
 {
@@ -583,7 +609,8 @@ convert_string (gchar *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)
+script_fu_marshal_procedure_call (scheme  *sc,
+                                  pointer  a)
 {
   GimpParam       *args;
   GimpParam       *values = NULL;
@@ -599,15 +626,10 @@ script_fu_marshal_procedure_call (scheme *sc, pointer a)
   gint             nreturn_vals;
   GimpParamDef    *params;
   GimpParamDef    *return_vals;
-  gchar            error_str[256];
+  gchar            error_str[1024];
   gint             i;
-  gint             j;
   gint             success = TRUE;
-  pointer          intermediate_val;
   pointer          return_val = sc->NIL;
-  gchar           *string;
-  gint32           n_elements;
-  pointer          vector;
 
 #if DEBUG_MARSHALL
 /* These three #defines are from Tinyscheme (tinyscheme/scheme.c) */
@@ -615,32 +637,16 @@ script_fu_marshal_procedure_call (scheme *sc, pointer a)
 #define typeflag(p) ((p)->_flag)
 #define type(p)     (typeflag(p)&T_MASKTYPE)
 
-char *ret_types[] = {
-  "GIMP_PDB_INT32",       "GIMP_PDB_INT16",     "GIMP_PDB_INT8",
-  "GIMP_PDB_FLOAT",       "GIMP_PDB_STRING",    "GIMP_PDB_INT32ARRAY",
-  "GIMP_PDB_INT16ARRAY",  "GIMP_PDB_INT8ARRAY", "GIMP_PDB_FLOATARRAY",
-  "GIMP_PDB_STRINGARRAY", "GIMP_PDB_COLOR",     "GIMP_PDB_REGION",
-  "GIMP_PDB_DISPLAY",     "GIMP_PDB_IMAGE",     "GIMP_PDB_LAYER",
-  "GIMP_PDB_CHANNEL",     "GIMP_PDB_DRAWABLE",  "GIMP_PDB_SELECTION",
-  "GIMP_PDB_BOUNDARY",    "GIMP_PDB_VECTORS",   "GIMP_PDB_PARASITE",
-  "GIMP_PDB_STATUS",      "GIMP_PDB_END"
-};
-
-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"
-};
-
-char *status_types[] = {
-  "GIMP_PDB_EXECUTION_ERROR", "GIMP_PDB_CALLING_ERROR",
-  "GIMP_PDB_PASS_THROUGH",    "GIMP_PDB_SUCCESS",
-  "GIMP_PDB_CANCEL"
-};
-
-g_printerr ("\nIn script_fu_marshal_procedure_call ()\n");
+  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  */
@@ -657,10 +663,8 @@ g_printerr ("\nIn script_fu_marshal_procedure_call ()\n");
     proc_name = g_strdup (sc->vptr->string_value (a));
 
 #ifdef DEBUG_MARSHALL
-g_printerr ("  proc name: %s\n", proc_name);
-#endif
-#if DEBUG_MARSHALL
-g_printerr ("  parms rcvd: %d\n", sc->vptr->list_length (sc, a)-1);
+  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  */
@@ -678,7 +682,7 @@ g_printerr ("  parms rcvd: %d\n", sc->vptr->list_length (sc, a)-1);
                                       &params, &return_vals))
     {
 #ifdef DEBUG_MARSHALL
-g_printerr ("  Invalid procedure name\n");
+      g_printerr ("  Invalid procedure name\n");
 #endif
       g_snprintf (error_str, sizeof (error_str),
                   "Invalid procedure name %s specified", proc_name);
@@ -698,11 +702,11 @@ g_printerr ("  Invalid procedure name\n");
     }
 
   /*  Check the supplied number of arguments  */
-  if ( (sc->vptr->list_length (sc, a) - 1) != nparams)
+  if ((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));
+      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)",
@@ -718,14 +722,26 @@ g_printerr ("  Invalid number of arguments (expected %d but received %d)",
 
   for (i = 0; i < nparams; i++)
     {
+      gint32  n_elements;
+      pointer vector;
+      gint    j;
+
       a = sc->vptr->pair_cdr (a);
 
 #if DEBUG_MARSHALL
-g_printerr ("    param %d - expecting type %s (%d)\n",
-                 i+1, ret_types[ params[i].type ], 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)));
+      {
+        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;
@@ -735,11 +751,11 @@ g_printerr ("      passed arg is type %s (%d)\n",
         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_BOUNDARY:
         case GIMP_PDB_VECTORS:
           if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
             success = FALSE;
@@ -747,7 +763,7 @@ g_printerr ("      passed arg is type %s (%d)\n",
             {
               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);
+              g_printerr ("      int32 arg is '%d'\n", args[i].data.d_int32);
 #endif
             }
           break;
@@ -759,7 +775,7 @@ g_printerr ("      int32 arg is '%d'\n", args[i].data.d_int32);
             {
               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);
+              g_printerr ("      int16 arg is '%d'\n", args[i].data.d_int16);
 #endif
             }
           break;
@@ -771,7 +787,7 @@ g_printerr ("      int16 arg is '%d'\n", args[i].data.d_int16);
             {
               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);
+              g_printerr ("      int8 arg is '%u'\n", args[i].data.d_int8);
 #endif
             }
           break;
@@ -783,7 +799,7 @@ g_printerr ("      int8 arg is '%u'\n", args[i].data.d_int8);
             {
               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);
+              g_printerr ("      float arg is '%f'\n", args[i].data.d_float);
 #endif
             }
           break;
@@ -795,7 +811,7 @@ g_printerr ("      float arg is '%f'\n", args[i].data.d_float);
             {
               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);
+              g_printerr ("      string arg is '%s'\n", args[i].data.d_string);
 #endif
             }
           break;
@@ -838,18 +854,18 @@ g_printerr ("      string arg is '%s'\n", args[i].data.d_string);
                 }
 
 #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");
-  }
-}
+              {
+                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;
@@ -889,18 +905,18 @@ if (count > 0)
                 }
 
 #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");
-  }
-}
+              {
+                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;
@@ -942,18 +958,18 @@ if (count > 0)
                 }
 
 #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");
-  }
-}
+              {
+                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;
@@ -995,18 +1011,18 @@ if (count > 0)
                 }
 
 #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");
-  }
-}
+              {
+                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;
@@ -1050,18 +1066,18 @@ if (count > 0)
                 }
 
 #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");
-  }
-}
+              {
+                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;
@@ -1076,8 +1092,8 @@ if (count > 0)
 
               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)));
+              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)) &&
@@ -1095,7 +1111,7 @@ g_printerr ("      (%s)\n",
 
               gimp_rgba_set_uchar (&args[i].data.d_color, r, g, b, 255);
 #if DEBUG_MARSHALL
-g_printerr ("      (%d %d %d)\n", r, g, b);
+              g_printerr ("      (%d %d %d)\n", r, g, b);
 #endif
             }
           else
@@ -1104,32 +1120,62 @@ g_printerr ("      (%d %d %d)\n", r, g, b);
             }
           break;
 
-        case GIMP_PDB_REGION:
-          if (! (sc->vptr->is_list (sc, sc->vptr->pair_car (a)) &&
-            sc->vptr->list_length (sc, sc->vptr->pair_car (a)) == 4))
+        case GIMP_PDB_COLORARRAY:
+          vector = sc->vptr->pair_car (a);
+          if (!sc->vptr->is_vector (vector))
             success = FALSE;
           if (success)
             {
-              pointer region;
-
-              region = sc->vptr->pair_car (a);
-              args[i].data.d_region.x =
-                           sc->vptr->ivalue (sc->vptr->pair_car (region));
-              region = sc->vptr->pair_cdr (region);
-              args[i].data.d_region.y =
-                           sc->vptr->ivalue (sc->vptr->pair_car (region));
-              region = sc->vptr->pair_cdr (region);
-              args[i].data.d_region.width =
-                           sc->vptr->ivalue (sc->vptr->pair_car (region));
-              region = sc->vptr->pair_cdr (region);
-              args[i].data.d_region.height =
-                           sc->vptr->ivalue (sc->vptr->pair_car (region));
+              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
-g_printerr ("      (%d %d %d %d)\n",
-                 args[i].data.d_region.x,
-                 args[i].data.d_region.y,
-                 args[i].data.d_region.width,
-                 args[i].data.d_region.height);
+              {
+                glong count = sc->vptr->vector_length (vector);
+                g_printerr ("      color vector has %ld elements\n", count);
+              }
 #endif
             }
           break;
@@ -1140,52 +1186,54 @@ g_printerr ("      (%d %d %d %d)\n",
             success = FALSE;
           if (success)
             {
+              pointer temp_val;
+
               /* parasite->name */
-              intermediate_val = sc->vptr->pair_car (a);
+              temp_val = sc->vptr->pair_car (a);
 
-              if (!sc->vptr->is_string (sc->vptr->pair_car (intermediate_val)))
+              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 (intermediate_val));
+                sc->vptr->string_value (sc->vptr->pair_car (temp_val));
 #if DEBUG_MARSHALL
-g_printerr ("      name '%s'\n", args[i].data.d_parasite.name);
+              g_printerr ("      name '%s'\n", args[i].data.d_parasite.name);
 #endif
 
               /* parasite->flags */
-              intermediate_val = sc->vptr->pair_cdr (intermediate_val);
+              temp_val = sc->vptr->pair_cdr (temp_val);
 
-              if (!sc->vptr->is_number (sc->vptr->pair_car (intermediate_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 (intermediate_val));
+                sc->vptr->ivalue (sc->vptr->pair_car (temp_val));
 #if DEBUG_MARSHALL
-g_printerr ("      flags %d", args[i].data.d_parasite.flags);
+              g_printerr ("      flags %d", args[i].data.d_parasite.flags);
 #endif
 
               /* parasite->data */
-              intermediate_val = sc->vptr->pair_cdr (intermediate_val);
+              temp_val = sc->vptr->pair_cdr (temp_val);
 
-              if (!sc->vptr->is_string (sc->vptr->pair_car (intermediate_val)))
+              if (!sc->vptr->is_string (sc->vptr->pair_car (temp_val)))
                 {
                   success = FALSE;
                   break;
                 }
 
-              args[i].data.d_parasite.size =
-                sc->vptr->ivalue (sc->vptr->pair_car (intermediate_val));
               args[i].data.d_parasite.data =
-                sc->vptr->string_value (sc->vptr->pair_car (intermediate_val));
+                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);
+              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;
@@ -1209,19 +1257,19 @@ g_printerr ("      data '%s'\n", (char *)args[i].data.d_parasite.data);
     }
 
   if (success)
+    {
 #if DEBUG_MARSHALL
-{
-g_printerr ("    calling %s...", proc_name);
+      g_printerr ("    calling %s...", proc_name);
 #endif
-    values = gimp_run_procedure2 (proc_name, &nvalues, nparams, args);
+      values = gimp_run_procedure2 (proc_name, &nvalues, nparams, args);
 #if DEBUG_MARSHALL
-g_printerr ("  done.\n");
-}
+      g_printerr ("  done.\n");
 #endif
+    }
   else
     {
 #if DEBUG_MARSHALL
-g_printerr ("  Invalid type for argument %d\n", i+1);
+      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",
@@ -1233,7 +1281,7 @@ g_printerr ("  Invalid type for argument %d\n", i+1);
   if (! values)
     {
 #if DEBUG_MARSHALL
-g_printerr ("  Did not return status\n");
+      g_printerr ("  Did not return status\n");
 #endif
       g_snprintf (error_str, sizeof(error_str),
                   "Procedure execution of %s did not return a status",
@@ -1243,76 +1291,107 @@ g_printerr ("  Did not return status\n");
     }
 
 #if DEBUG_MARSHALL
-g_printerr ("    return value is %s\n",
-                 status_types[ values[0].data.d_status ]);
+  {
+    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:
-      g_snprintf (error_str, sizeof (error_str),
-                  "Procedure execution of %s failed",
-                  proc_name);
+      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:
-      g_snprintf (error_str, sizeof (error_str),
-                  "Procedure execution of %s failed on invalid input arguments",
-                  proc_name);
+      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);
+      g_printerr ("    values returned: %d\n", nvalues-1);
 #endif
       for (i = nvalues - 2; i >= 0; --i)
         {
+          const gchar *string;
+          gint         j;
+
 #if DEBUG_MARSHALL
-g_printerr ("      value %d is type %s (%d)\n",
-                 i, ret_types[ return_vals[i].type ], return_vals[i].type);
+          {
+            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_BOUNDARY:
             case GIMP_PDB_VECTORS:
               return_val = sc->vptr->cons (sc,
                              sc->vptr->mk_integer (sc,
                                                    values[i + 1].data.d_int32),
-                                                   return_val);
-              set_safe_foreign (sc, return_val);
+                             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);
-              set_safe_foreign (sc, return_val);
+                             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);
-              set_safe_foreign (sc, return_val);
+                             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);
-              set_safe_foreign (sc, return_val);
+                             return_val);
               break;
 
             case GIMP_PDB_STRING:
@@ -1320,64 +1399,49 @@ g_printerr ("      value %d is type %s (%d)\n",
               if (! string)
                 string = "";
               return_val = sc->vptr->cons (sc,
-                                           sc->vptr->mk_string (sc, string),
-                                           return_val);
-              set_safe_foreign (sc, return_val);
+                             sc->vptr->mk_string (sc, string),
+                             return_val);
               break;
 
             case GIMP_PDB_INT32ARRAY:
-              /*  integer arrays are always implemented such that the previous
-               *  return value contains the number of strings in the array
-               */
               {
                 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);
 
-                return_val = sc->vptr->cons (sc, vector, return_val);
-                set_safe_foreign (sc, return_val);
-
                 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:
-              /*  integer arrays are always implemented such that the previous
-               *  return value contains the number of strings in the array
-               */
               {
                 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);
 
-                return_val = sc->vptr->cons (sc, vector, return_val);
-                set_safe_foreign (sc, return_val);
-
                 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:
-              /*  integer arrays are always implemented such that the previous
-               *  return value contains the number of strings in the array
-               */
               {
-                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);
-
-                return_val = sc->vptr->cons (sc, vector, return_val);
-                set_safe_foreign (sc, return_val);
+                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++)
                   {
@@ -1385,20 +1449,16 @@ g_printerr ("      value %d is type %s (%d)\n",
                                                sc->vptr->mk_integer (sc,
                                                                      array[j]));
                   }
+
+                return_val = sc->vptr->cons (sc, vector, return_val);
               }
               break;
 
             case GIMP_PDB_FLOATARRAY:
-              /*  float arrays are always implemented such that the previous
-               *  return value contains the number of strings in the array
-               */
               {
                 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);
-
-                return_val = sc->vptr->cons (sc, vector, return_val);
-                set_safe_foreign (sc, return_val);
+                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++)
                   {
@@ -1406,114 +1466,113 @@ g_printerr ("      value %d is type %s (%d)\n",
                                                sc->vptr->mk_real (sc,
                                                                   array[j]));
                   }
+
+                return_val = sc->vptr->cons (sc, vector, return_val);
               }
               break;
 
             case GIMP_PDB_STRINGARRAY:
-              /*  string arrays are always implemented such that the previous
-               *  return value contains the number of strings in the array
-               */
               {
                 gint    num_strings = values[i].data.d_int32;
-                gchar **array  = (gchar **) values[i + 1].data.d_stringarray;
-                pointer list   = sc->NIL;
-
-                return_val = sc->vptr->cons (sc, list, return_val);
-                set_safe_foreign (sc, return_val);
+                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] : ""),
+                                           sc->vptr->mk_string (sc,
+                                                                array[j] ?
+                                                                array[j] : ""),
                                            list);
-
-                    /* hook the current list into return_val, so that it
-                     * inherits the set_safe_foreign()-protection.
-                     * May be removed when tinyscheme fixes the GC issue
-                     * with foreign functions */
-                    sc->vptr->set_car (return_val, list);
                   }
+
+                return_val = sc->vptr->cons (sc, list, return_val);
               }
               break;
 
             case GIMP_PDB_COLOR:
               {
-                guchar r, g, b;
+                guchar   r, g, b;
+                gpointer temp_val;
 
                 gimp_rgb_get_uchar (&values[i + 1].data.d_color, &r, &g, &b);
 
-                intermediate_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)));
+                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,
-                                             intermediate_val,
+                                             temp_val,
                                              return_val);
-                set_safe_foreign (sc, return_val);
                 break;
               }
 
-            case GIMP_PDB_REGION:
+            case GIMP_PDB_COLORARRAY:
               {
-                gint32 x, y, w, h;
-
-                x = values[i + 1].data.d_region.x;
-                y = values[i + 1].data.d_region.y;
-                w = values[i + 1].data.d_region.width;
-                h = values[i + 1].data.d_region.height;
-
-                intermediate_val = sc->vptr->cons (sc,
-                    sc->vptr->mk_integer (sc, x),
-                    sc->vptr->cons (sc,
-                        sc->vptr->mk_integer (sc, y),
-                        sc->vptr->cons (sc,
-                            sc->vptr->mk_integer (sc, w),
-                            sc->vptr->cons (sc,
-                                sc->vptr->mk_integer (sc, h),
-                                sc->NIL))));
-                return_val = sc->vptr->cons (sc,
-                                             intermediate_val,
-                                             return_val);
-                set_safe_foreign (sc, return_val);
-                break;
+                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!  */
-                    intermediate_val = sc->vptr->cons (sc,
-                        sc->vptr->mk_string (sc,
-                                             values[i + 1].data.d_parasite.name),
-                        sc->vptr->cons (sc,
-                            sc->vptr->mk_integer (sc,
-                                                  values[i + 1].data.d_parasite.flags),
-                            sc->vptr->cons (sc,
-                                sc->vptr->mk_counted_string (sc,
-                                                             values[i + 1].data.d_parasite.data,
-                                                             values[i + 1].data.d_parasite.size),
-                                 sc->NIL)));
+                     * 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,
-                                                 intermediate_val,
+                                                 temp_val,
                                                  return_val);
-                    set_safe_foreign (sc, return_val);
+                    g_free (data);
 
 #if DEBUG_MARSHALL
-g_printerr ("      name '%s'\n", values[i+1].data.d_parasite.name);
-g_printerr ("      flags %d", values[i+1].data.d_parasite.flags);
-g_printerr (", size %d\n", values[i+1].data.d_parasite.size);
-g_printerr ("      data '%.*s'\n",
-                 values[i+1].data.d_parasite.size,
-                 (char *)values[i+1].data.d_parasite.data);
+                    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
                   }
               }
@@ -1533,14 +1592,15 @@ g_printerr ("      data '%.*s'\n",
       break;
     }
 
-  /* If we have no return value(s) from PDB call, return */
-  /* either TRUE or FALSE to indicate if call succeeded. */
+  /* 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);
+        return_val = sc->vptr->cons (sc, sc->T, sc->NIL);
       else
-         return_val = sc->vptr->cons (sc, sc->F, sc->NIL);
+        return_val = sc->vptr->cons (sc, sc->F, sc->NIL);
     }
 
   /*  free the proc name  */
@@ -1572,7 +1632,6 @@ g_printerr ("      data '%.*s'\n",
 #endif
 
   return return_val;
-
 }
 
 static void
@@ -1612,15 +1671,18 @@ script_fu_marshal_destroy_args (GimpParam *params,
           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_REGION:
         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_BOUNDARY:
         case GIMP_PDB_VECTORS:
         case GIMP_PDB_PARASITE:
         case GIMP_PDB_STATUS:
@@ -1633,25 +1695,22 @@ script_fu_marshal_destroy_args (GimpParam *params,
 }
 
 static pointer
-script_fu_register_call (scheme *sc, pointer a)
+script_fu_register_call (scheme  *sc,
+                         pointer  a)
 {
-  if (register_scripts)
-    return script_fu_add_script (sc, a);
-  else
-    return sc->NIL;
+  return script_fu_add_script (sc, a);
 }
 
 static pointer
-script_fu_menu_register_call (scheme *sc, pointer a)
+script_fu_menu_register_call (scheme  *sc,
+                              pointer  a)
 {
-  if (register_scripts)
-    return script_fu_add_menu (sc, a);
-  else
-    return sc->NIL;
+  return script_fu_add_menu (sc, a);
 }
 
 static pointer
-script_fu_quit_call (scheme *sc, pointer a)
+script_fu_quit_call (scheme  *sc,
+                     pointer  a)
 {
   script_fu_server_quit ();
 
@@ -1659,3 +1718,10 @@ script_fu_quit_call (scheme *sc, pointer a)
 
   return sc->NIL;
 }
+
+static pointer
+script_fu_nil_call (scheme  *sc,
+                    pointer  a)
+{
+  return sc->NIL;
+}
diff --git a/tiny-fu/scheme-wrapper.h b/tiny-fu/scheme-wrapper.h
index 6ffa3ed..9ca416d 100644
--- a/tiny-fu/scheme-wrapper.h
+++ b/tiny-fu/scheme-wrapper.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,39 +12,36 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef SCHEME_WRAPPER_H
-#define SCHEME_WRAPPER_H
+#ifndef __SCHEME_WRAPPER_H__
+#define __SCHEME_WRAPPER_H__
 
 #include "tinyscheme/scheme.h"
 
-void          ts_stdout_output_func   (TsOutputType    type,
-                                       const char     *string,
-                                       int             len,
-                                       gpointer        user_data);
+void          tinyscheme_init         (const gchar  *path,
+                                       gboolean      register_scripts);
 
-void          ts_gstring_output_func  (TsOutputType    type,
-                                       const char     *string,
-                                       int             len,
-                                       gpointer        user_data);
+void          ts_set_run_mode         (GimpRunMode   run_mode);
 
-void          ts_set_print_flag    (gint);
-void          ts_print_welcome     (void);
+void          ts_set_print_flag       (gint          print_flag);
+void          ts_print_welcome        (void);
 
-const gchar * ts_get_success_msg   (void);
+const gchar * ts_get_success_msg      (void);
 
-void          tinyscheme_init      (const gchar  *path,
-                                    gboolean      local_register_scripts);
-void          tinyscheme_deinit    (void);
-
-void          set_run_mode_constant (GimpRunMode run_mode);
-
-void          ts_interpret_stdin   (void);
+void          ts_interpret_stdin      (void);
 
 /* if the return value is 0, success. error otherwise. */
-gint          ts_interpret_string  (const gchar *);
-
-#endif /* SCHEME_WRAPPER_H */
+gint          ts_interpret_string     (const gchar  *expr);
+
+void          ts_stdout_output_func   (TsOutputType  type,
+                                       const char   *string,
+                                       int           len,
+                                       gpointer      user_data);
+void          ts_gstring_output_func  (TsOutputType  type,
+                                       const char   *string,
+                                       int           len,
+                                       gpointer      user_data);
+
+#endif /* __SCHEME_WRAPPER_H__ */
diff --git a/tiny-fu/tiny-fu-console.c b/tiny-fu/tiny-fu-console.c
index 12a2332..db7b158 100644
--- a/tiny-fu/tiny-fu-console.c
+++ b/tiny-fu/tiny-fu-console.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -28,8 +27,6 @@
 
 #include <gdk/gdkkeysyms.h>
 
-#include "tinyscheme/scheme.h"
-
 #include "scheme-wrapper.h"
 #include "tiny-fu-console.h"
 
@@ -39,7 +36,7 @@
 #define TEXT_WIDTH  480
 #define TEXT_HEIGHT 400
 
-#define PROC_NAME   "plug-in-script-fu-console"
+#define PROC_NAME   "plug-in-tiny-fu-console"
 
 typedef struct
 {
@@ -125,13 +122,13 @@ script_fu_console_interface (void)
   GtkWidget        *scrolled_window;
   GtkWidget        *hbox;
 
-  gimp_ui_init ("script-fu", FALSE);
+  gimp_ui_init ("tiny-fu", FALSE);
 
   console.input_id    = -1;
   console.history_max = 50;
 
-  console.dialog = gimp_dialog_new (_("Script-Fu Console"),
-                                    "script-fu-console",
+  console.dialog = gimp_dialog_new (_("Tiny-Fu Console"),
+                                    "gimp-tiny-fu-console",
                                     NULL, 0,
                                     gimp_standard_help_func, PROC_NAME,
 
@@ -155,10 +152,10 @@ script_fu_console_interface (void)
                     &console);
 
   /*  The main vbox  */
-  vbox = gtk_vbox_new (FALSE, 12);
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
   gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (console.dialog)->vbox), vbox,
-                      TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (console.dialog))),
+                      vbox, TRUE, TRUE, 0);
   gtk_widget_show (vbox);
 
   /*  The output text widget  */
@@ -197,7 +194,7 @@ script_fu_console_interface (void)
       NULL,       "\n",
       NULL,       "Copyright (c) Dimitrios Souflis",
       NULL,       "\n",
-      "strong",   N_("Script-Fu Console"),
+      "strong",   N_("Tiny-Fu Console"),
       NULL,       " - ",
       "emphasis", N_("Interactive Scheme Development"),
       NULL,       "\n"
@@ -222,7 +219,7 @@ script_fu_console_interface (void)
   }
 
   /*  The current command  */
-  hbox = gtk_hbox_new (FALSE, 6);
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
   gtk_widget_show (hbox);
 
@@ -236,7 +233,7 @@ script_fu_console_interface (void)
                     &console);
 
   button = gtk_button_new_with_mnemonic (_("_Browse..."));
-  gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
+  gtk_misc_set_padding (GTK_MISC (gtk_bin_get_child (GTK_BIN (button))), 2, 0);
   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
   gtk_widget_show (button);
 
@@ -293,7 +290,7 @@ script_fu_console_save_dialog (ConsoleInterface *console)
   if (! console->save_dialog)
     {
       console->save_dialog =
-        gtk_file_chooser_dialog_new (_("Save Script-Fu Console Output"),
+        gtk_file_chooser_dialog_new (_("Save Tiny-Fu Console Output"),
                                      GTK_WINDOW (console->dialog),
                                      GTK_FILE_CHOOSER_ACTION_SAVE,
                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
@@ -369,8 +366,8 @@ script_fu_browse_callback (GtkWidget        *widget,
   if (! console->proc_browser)
     {
       console->proc_browser =
-        gimp_proc_browser_dialog_new (_("Script-Fu Procedure Browser"),
-                                      "script-fu-procedure-browser",
+        gimp_proc_browser_dialog_new (_("Tiny-Fu Procedure Browser"),
+                                      "tiny-fu-procedure-browser",
                                       gimp_standard_help_func, PROC_NAME,
 
                                       GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
@@ -485,9 +482,18 @@ script_fu_browse_row_activated (GtkDialog *dialog)
 static gboolean
 script_fu_console_idle_scroll_end (GtkWidget *view)
 {
-  GtkAdjustment *adj = GTK_TEXT_VIEW (view)->vadjustment;
+  GtkWidget *parent = gtk_widget_get_parent (view);
+
+  if (parent)
+    {
+      GtkAdjustment *adj;
+
+      adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (parent));
 
-  gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
+      gtk_adjustment_set_value (adj,
+                                gtk_adjustment_get_upper (adj) -
+                                gtk_adjustment_get_page_size (adj));
+    }
 
   g_object_unref (view);
 
@@ -514,10 +520,13 @@ script_fu_output_to_console (TsOutputType  type,
 
   if (console && console->text_view)
     {
-      GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (console->text_view));
+      GtkTextBuffer *buffer;
       GtkTextIter    cursor;
 
+      buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (console->text_view));
+
       gtk_text_buffer_get_end_iter (buffer, &cursor);
+
       if (type == TS_OUTPUT_NORMAL)
         {
           gtk_text_buffer_insert (buffer, &cursor, text, len);
@@ -528,6 +537,7 @@ script_fu_output_to_console (TsOutputType  type,
                                                     text, len, "emphasis",
                                                     NULL);
         }
+
       script_fu_console_scroll_end (console->text_view);
     }
 }
@@ -563,7 +573,9 @@ script_fu_cc_key_function (GtkWidget        *widget,
 
   switch (event->keyval)
     {
-    case GDK_Return:
+    case GDK_KEY_Return:
+    case GDK_KEY_KP_Enter:
+    case GDK_KEY_ISO_Enter:
       if (script_fu_cc_is_empty (console))
         return TRUE;
 
@@ -591,8 +603,11 @@ script_fu_cc_key_function (GtkWidget        *widget,
 
       gtk_entry_set_text (GTK_ENTRY (console->cc), "");
 
-      output = g_string_new ("");
+      output = g_string_new (NULL);
       ts_register_output_func (ts_gstring_output_func, output);
+
+      gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_PLUGIN);
+
       if (ts_interpret_string (list->data) != 0)
         {
           script_fu_output_to_console (TS_OUTPUT_ERROR,
@@ -607,6 +622,9 @@ script_fu_cc_key_function (GtkWidget        *widget,
                                        output->len,
                                        console);
         }
+
+      gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_INTERNAL);
+
       g_string_free (output, TRUE);
 
       gimp_displays_flush ();
@@ -630,24 +648,24 @@ script_fu_cc_key_function (GtkWidget        *widget,
       return TRUE;
       break;
 
-    case GDK_KP_Up:
-    case GDK_Up:
+    case GDK_KEY_KP_Up:
+    case GDK_KEY_Up:
       direction = -1;
       break;
 
-    case GDK_KP_Down:
-    case GDK_Down:
+    case GDK_KEY_KP_Down:
+    case GDK_KEY_Down:
       direction = 1;
       break;
 
-    case GDK_P:
-    case GDK_p:
+    case GDK_KEY_P:
+    case GDK_KEY_p:
       if (event->state & GDK_CONTROL_MASK)
         direction = -1;
       break;
 
-    case GDK_N:
-    case GDK_n:
+    case GDK_KEY_N:
+    case GDK_KEY_n:
       if (event->state & GDK_CONTROL_MASK)
         direction = 1;
       break;
@@ -686,44 +704,3 @@ script_fu_cc_key_function (GtkWidget        *widget,
 
   return FALSE;
 }
-
-void
-script_fu_eval_run (const gchar      *name,
-                    gint              nparams,
-                    const GimpParam  *params,
-                    gint             *nreturn_vals,
-                    GimpParam       **return_vals)
-{
-  static GimpParam  values[1];
-  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
-  GimpRunMode       run_mode;
-
-  run_mode = params[0].data.d_int32;
-  set_run_mode_constant (run_mode);
-
-  switch (run_mode)
-    {
-    case GIMP_RUN_NONINTERACTIVE:
-      /*  Disable Script-Fu output  */
-      ts_register_output_func (NULL, NULL);
-      if (ts_interpret_string (params[1].data.d_string) != 0)
-          status = GIMP_PDB_EXECUTION_ERROR;
-      break;
-
-    case GIMP_RUN_INTERACTIVE:
-    case GIMP_RUN_WITH_LAST_VALS:
-      status = GIMP_PDB_CALLING_ERROR;
-      g_message (_("Script-Fu evaluation mode only allows "
-                   "non-interactive invocation"));
-      break;
-
-    default:
-      break;
-    }
-
-  *nreturn_vals = 1;
-  *return_vals = values;
-
-  values[0].type          = GIMP_PDB_STATUS;
-  values[0].data.d_status = status;
-}
diff --git a/tiny-fu/tiny-fu-console.h b/tiny-fu/tiny-fu-console.h
index 881a2a2..a1c80ca 100644
--- a/tiny-fu/tiny-fu-console.h
+++ b/tiny-fu/tiny-fu-console.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,24 +12,18 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_CONSOLE_H__
 #define __SCRIPT_FU_CONSOLE_H__
 
 
-void   script_fu_console_run       (const gchar      *name,
-                                    gint              nparams,
-                                    const GimpParam  *params,
-                                    gint             *nreturn_vals,
-                                    GimpParam       **return_vals);
-void   script_fu_eval_run          (const gchar      *name,
-                                    gint              nparams,
-                                    const GimpParam  *params,
-                                    gint             *nreturn_vals,
-                                    GimpParam       **return_vals);
+void  script_fu_console_run (const gchar      *name,
+                             gint              nparams,
+                             const GimpParam  *params,
+                             gint             *nreturn_vals,
+                             GimpParam       **return_vals);
 
 
-#endif /*  __SCRIPT_FU_CONSOLE__  */
+#endif /*  __SCRIPT_FU_CONSOLE_H__  */
diff --git a/tiny-fu/tiny-fu-enums.h b/tiny-fu/tiny-fu-enums.h
index 21bcafb..3c42c95 100644
--- a/tiny-fu/tiny-fu-enums.h
+++ b/tiny-fu/tiny-fu-enums.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_ENUMS_H__
diff --git a/tiny-fu/tiny-fu-eval.c b/tiny-fu/tiny-fu-eval.c
new file mode 100644
index 0000000..af98617
--- /dev/null
+++ b/tiny-fu/tiny-fu-eval.c
@@ -0,0 +1,80 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "libgimp/gimp.h"
+
+#include "scheme-wrapper.h"
+#include "tiny-fu-eval.h"
+
+#include "tiny-fu-intl.h"
+
+
+void
+script_fu_eval_run (const gchar      *name,
+                    gint              nparams,
+                    const GimpParam  *params,
+                    gint             *nreturn_vals,
+                    GimpParam       **return_vals)
+{
+  static GimpParam   values[2];
+  GString           *output = g_string_new (NULL);
+  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+  GimpRunMode        run_mode;
+
+  *nreturn_vals = 1;
+  *return_vals  = values;
+
+  values[0].type = GIMP_PDB_STATUS;
+
+  run_mode = params[0].data.d_int32;
+
+  ts_set_run_mode (run_mode);
+  ts_register_output_func (ts_gstring_output_func, output);
+
+  switch (run_mode)
+    {
+    case GIMP_RUN_NONINTERACTIVE:
+      if (ts_interpret_string (params[1].data.d_string) != 0)
+        status = GIMP_PDB_EXECUTION_ERROR;
+      break;
+
+    case GIMP_RUN_INTERACTIVE:
+    case GIMP_RUN_WITH_LAST_VALS:
+      status        = GIMP_PDB_CALLING_ERROR;
+      g_string_assign (output, _("Tiny-Fu evaluation mode only allows "
+                                 "non-interactive invocation"));
+      break;
+
+    default:
+      break;
+    }
+
+  values[0].data.d_status = status;
+
+  if (status != GIMP_PDB_SUCCESS && output->len > 0)
+    {
+      *nreturn_vals = 2;
+      values[1].type          = GIMP_PDB_STRING;
+      values[1].data.d_string = g_string_free (output, FALSE);
+    }
+  else
+    {
+      g_string_free (output, TRUE);
+    }
+}
diff --git a/tiny-fu/tiny-fu-eval.h b/tiny-fu/tiny-fu-eval.h
new file mode 100644
index 0000000..0bc335e
--- /dev/null
+++ b/tiny-fu/tiny-fu-eval.h
@@ -0,0 +1,29 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_EVAL_H__
+#define __SCRIPT_FU_EVAL_H__
+
+
+void  script_fu_eval_run (const gchar      *name,
+                          gint              nparams,
+                          const GimpParam  *params,
+                          gint             *nreturn_vals,
+                          GimpParam       **return_vals);
+
+
+#endif /*  __SCRIPT_FU_EVAL_H__  */
diff --git a/tiny-fu/tiny-fu-interface.c b/tiny-fu/tiny-fu-interface.c
index 3106349..bb6aa24 100644
--- a/tiny-fu/tiny-fu-interface.c
+++ b/tiny-fu/tiny-fu-interface.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -30,6 +29,7 @@
 
 #include "tiny-fu-interface.h"
 #include "tiny-fu-scripts.h"
+#include "tiny-fu-script.h"
 
 #include "tiny-fu-intl.h"
 
@@ -108,8 +108,11 @@ static void   script_fu_brush_callback      (gpointer              data,
  *  Local variables
  */
 
-static SFInterface *sf_interface = NULL;  /*  there can only be at most one
-                                              interactive interface  */
+static SFInterface       *sf_interface = NULL;  /*  there can only be at most
+                                                 *  one interactive interface
+                                                 */
+
+static GimpPDBStatusType  sf_status    = GIMP_PDB_SUCCESS;
 
 
 /*
@@ -153,7 +156,8 @@ script_fu_interface_report_cc (const gchar *command)
 
       if (! g_str_has_prefix (command, "gimp-progress-"))
         {
-          gtk_label_set_text (GTK_LABEL (sf_interface->progress_label), command);
+          gtk_label_set_text (GTK_LABEL (sf_interface->progress_label),
+                              command);
         }
       else
         {
@@ -165,80 +169,60 @@ script_fu_interface_report_cc (const gchar *command)
     gtk_main_iteration ();
 }
 
-void
-script_fu_interface (SFScript *script,
-                     gint      start_arg)
+GimpPDBStatusType
+script_fu_interface (SFScript  *script,
+                     gint       start_arg)
 {
   GtkWidget    *dialog;
-  GtkWidget    *menu;
   GtkWidget    *vbox;
   GtkWidget    *vbox2;
   GtkSizeGroup *group;
   GSList       *list;
-  gchar        *tmp;
   gchar        *title;
   gint          i;
 
   static gboolean gtk_initted = FALSE;
 
-  /*  Simply return if there is already an interface. This is an
-      ugly workaround for the fact that we can not process two
-      scripts at a time.  */
+  /* Simply return if there is already an interface. This is an
+   * ugly workaround for the fact that we can not process two
+   * scripts at a time.
+   */
   if (sf_interface != NULL)
     {
       gchar *message =
         g_strdup_printf ("%s\n\n%s",
-                         _("Script-Fu cannot process two scripts "
+                         _("Tiny-Fu cannot process two scripts "
                            "at the same time."),
                          _("You are already running the \"%s\" script."));
 
       g_message (message, sf_interface->title);
       g_free (message);
 
-      return;
+      return GIMP_PDB_CANCEL;
     }
 
-  g_return_if_fail (script != NULL);
+  g_return_val_if_fail (script != NULL, FALSE);
 
   if (!gtk_initted)
     {
       INIT_I18N();
 
-      gimp_ui_init ("script-fu", TRUE);
+      gimp_ui_init ("tiny-fu", TRUE);
 
       gtk_initted = TRUE;
     }
 
-  sf_interface = g_slice_new0 (SFInterface);
-
-  sf_interface->widgets = g_new0 (GtkWidget *, script->num_args);
-
-  /* strip mnemonics from the menupath */
-  sf_interface->title = gimp_strip_uline (gettext (script->menu_path));
-
-  /* if this looks like a full menu path, use only the last part */
-  if (sf_interface->title[0] == '<' &&
-      (tmp = strrchr (sf_interface->title, '/')) && tmp[1])
-    {
-      tmp = g_strdup (tmp + 1);
+  sf_status = GIMP_PDB_SUCCESS;
 
-      g_free (sf_interface->title);
-      sf_interface->title = tmp;
-    }
-
-  /* cut off ellipsis */
-  tmp = (strstr (sf_interface->title, "..."));
-  if (! tmp)
-    /* U+2026 HORIZONTAL ELLIPSIS */
-    tmp = strstr (sf_interface->title, "\342\200\246");
+  sf_interface = g_slice_new0 (SFInterface);
 
-  if (tmp && tmp == (sf_interface->title + strlen (sf_interface->title) - 3))
-    *tmp = '\0';
+  sf_interface->widgets = g_new0 (GtkWidget *, script->n_args);
+  sf_interface->title   = script_fu_script_get_title (script);
 
-  title = g_strdup_printf (_("Script-Fu: %s"), sf_interface->title);
+  title = g_strdup_printf (_("Tiny-Fu: %s"), sf_interface->title);
 
   sf_interface->dialog = dialog =
-    gimp_dialog_new (title, "script-fu",
+    gimp_dialog_new (title, "gimp-tiny-fu",
                      NULL, 0,
                      gimp_standard_help_func, script->name,
 
@@ -249,7 +233,7 @@ script_fu_interface (SFScript *script,
                      NULL);
   g_free (title);
 
-  gtk_dialog_set_alternative_button_order (GTK_DIALOG (sf_interface->dialog),
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
                                            RESPONSE_RESET,
                                            GTK_RESPONSE_OK,
                                            GTK_RESPONSE_CANCEL,
@@ -267,14 +251,14 @@ script_fu_interface (SFScript *script,
 
   gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
 
-  vbox = gtk_vbox_new (FALSE, 12);
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
   gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                       vbox, TRUE, TRUE, 0);
   gtk_widget_show (vbox);
 
   /*  The argument table  */
-  sf_interface->table = gtk_table_new (script->num_args - start_arg, 3, FALSE);
+  sf_interface->table = gtk_table_new (script->n_args - start_arg, 3, FALSE);
 
   gtk_table_set_col_spacings (GTK_TABLE (sf_interface->table), 6);
   gtk_table_set_row_spacings (GTK_TABLE (sf_interface->table), 6);
@@ -283,7 +267,7 @@ script_fu_interface (SFScript *script,
 
   group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
-  for (i = start_arg; i < script->num_args; i++)
+  for (i = start_arg; i < script->n_args; i++)
     {
       GtkWidget *widget       = NULL;
       GtkObject *adj;
@@ -292,263 +276,262 @@ script_fu_interface (SFScript *script,
       gint      *ID_ptr       = NULL;
       gint       row          = i;
       gboolean   left_align   = FALSE;
+      SFArg     *arg          = &script->args[i];
 
       row -= start_arg;
 
       /*  we add a colon after the label;
-          some languages want an extra space here  */
-      label_text = g_strdup_printf (_("%s:"), gettext (script->arg_labels[i]));
+       *  some languages want an extra space here
+       */
+      label_text = g_strdup_printf (_("%s:"), gettext (arg->label));
 
-      switch (script->arg_types[i])
-      {
-      case SF_IMAGE:
-      case SF_DRAWABLE:
-      case SF_LAYER:
-      case SF_CHANNEL:
-      case SF_VECTORS:
-        switch (script->arg_types[i])
-          {
-          case SF_IMAGE:
-            widget = gimp_image_combo_box_new (NULL, NULL);
-            ID_ptr = &script->arg_values[i].sfa_image;
-            break;
-
-          case SF_DRAWABLE:
-            widget = gimp_drawable_combo_box_new (NULL, NULL);
-            ID_ptr = &script->arg_values[i].sfa_drawable;
-            break;
-
-          case SF_LAYER:
-            widget = gimp_layer_combo_box_new (NULL, NULL);
-            ID_ptr = &script->arg_values[i].sfa_layer;
-            break;
-
-          case SF_CHANNEL:
-            widget = gimp_channel_combo_box_new (NULL, NULL);
-            ID_ptr = &script->arg_values[i].sfa_channel;
-            break;
-
-          case SF_VECTORS:
-            widget = gimp_vectors_combo_box_new (NULL, NULL);
-            ID_ptr = &script->arg_values[i].sfa_vectors;
-            break;
-
-          default:
-            menu = NULL;
-            break;
-          }
+      switch (arg->type)
+        {
+        case SF_IMAGE:
+        case SF_DRAWABLE:
+        case SF_LAYER:
+        case SF_CHANNEL:
+        case SF_VECTORS:
+          switch (arg->type)
+            {
+            case SF_IMAGE:
+              widget = gimp_image_combo_box_new (NULL, NULL);
+              ID_ptr = &arg->value.sfa_image;
+              break;
+
+            case SF_DRAWABLE:
+              widget = gimp_drawable_combo_box_new (NULL, NULL);
+              ID_ptr = &arg->value.sfa_drawable;
+              break;
+
+            case SF_LAYER:
+              widget = gimp_layer_combo_box_new (NULL, NULL);
+              ID_ptr = &arg->value.sfa_layer;
+              break;
+
+            case SF_CHANNEL:
+              widget = gimp_channel_combo_box_new (NULL, NULL);
+              ID_ptr = &arg->value.sfa_channel;
+              break;
+
+            case SF_VECTORS:
+              widget = gimp_vectors_combo_box_new (NULL, NULL);
+              ID_ptr = &arg->value.sfa_vectors;
+              break;
+
+            default:
+              break;
+            }
 
           gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (widget), *ID_ptr,
                                       G_CALLBACK (gimp_int_combo_box_get_active),
                                       ID_ptr);
-        break;
-
-      case SF_COLOR:
-        left_align = TRUE;
-        widget = gimp_color_button_new (_("Script-Fu Color Selection"),
-                                        COLOR_SAMPLE_WIDTH,
-                                        COLOR_SAMPLE_HEIGHT,
-                                        &script->arg_values[i].sfa_color,
-                                        GIMP_COLOR_AREA_FLAT);
+          break;
 
-        gimp_color_button_set_update (GIMP_COLOR_BUTTON (widget), TRUE);
+        case SF_COLOR:
+          left_align = TRUE;
+          widget = gimp_color_button_new (_("Tiny-Fu Color Selection"),
+                                          COLOR_SAMPLE_WIDTH,
+                                          COLOR_SAMPLE_HEIGHT,
+                                          &arg->value.sfa_color,
+                                          GIMP_COLOR_AREA_FLAT);
+
+          gimp_color_button_set_update (GIMP_COLOR_BUTTON (widget), TRUE);
+
+          g_signal_connect (widget, "color-changed",
+                            G_CALLBACK (gimp_color_button_get_color),
+                            &arg->value.sfa_color);
+          break;
 
-        g_signal_connect (widget, "color-changed",
-                          G_CALLBACK (gimp_color_button_get_color),
-                          &script->arg_values[i].sfa_color);
-        break;
+        case SF_TOGGLE:
+          g_free (label_text);
+          label_text = NULL;
+          widget = gtk_check_button_new_with_mnemonic (gettext (arg->label));
+          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
+                                        arg->value.sfa_toggle);
 
-      case SF_TOGGLE:
-        g_free (label_text);
-        label_text = NULL;
-        widget =
-              gtk_check_button_new_with_mnemonic (gettext (script->arg_labels[i]));
-        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
-                                      script->arg_values[i].sfa_toggle);
-
-        g_signal_connect (widget, "toggled",
-                          G_CALLBACK (gimp_toggle_button_update),
-                          &script->arg_values[i].sfa_toggle);
-        break;
+          g_signal_connect (widget, "toggled",
+                            G_CALLBACK (gimp_toggle_button_update),
+                            &arg->value.sfa_toggle);
+          break;
 
-      case SF_VALUE:
-      case SF_STRING:
-        widget = gtk_entry_new ();
-        gtk_widget_set_size_request (widget, TEXT_WIDTH, -1);
-        gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+        case SF_VALUE:
+        case SF_STRING:
+          widget = gtk_entry_new ();
+          gtk_widget_set_size_request (widget, TEXT_WIDTH, -1);
+          gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
 
-        gtk_entry_set_text (GTK_ENTRY (widget),
-                            script->arg_values[i].sfa_value);
-        break;
+          gtk_entry_set_text (GTK_ENTRY (widget), arg->value.sfa_value);
+          break;
 
-      case SF_TEXT:
-        {
-          GtkWidget     *view;
-          GtkTextBuffer *buffer;
-
-          widget = gtk_scrolled_window_new (NULL, NULL);
-          gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget),
-                                               GTK_SHADOW_IN);
-          gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
-                                          GTK_POLICY_AUTOMATIC,
-                                          GTK_POLICY_AUTOMATIC);
-          gtk_widget_set_size_request (widget, TEXT_WIDTH, -1);
+        case SF_TEXT:
+          {
+            GtkWidget     *view;
+            GtkTextBuffer *buffer;
 
-          view = gtk_text_view_new ();
-          gtk_container_add (GTK_CONTAINER (widget), view);
-          gtk_widget_show (view);
+            widget = gtk_scrolled_window_new (NULL, NULL);
+            gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget),
+                                                 GTK_SHADOW_IN);
+            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
+                                            GTK_POLICY_AUTOMATIC,
+                                            GTK_POLICY_AUTOMATIC);
+            gtk_widget_set_size_request (widget, TEXT_WIDTH, -1);
 
-          buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-          gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
+            view = gtk_text_view_new ();
+            gtk_container_add (GTK_CONTAINER (widget), view);
+            gtk_widget_show (view);
 
-          gtk_text_buffer_set_text (buffer,
-                                    script->arg_values[i].sfa_value, -1);
+            buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+            gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
 
-          label_yalign = 0.0;
-        }
-        break;
+            gtk_text_buffer_set_text (buffer, arg->value.sfa_value, -1);
 
-      case SF_ADJUSTMENT:
-        switch (script->arg_defaults[i].sfa_adjustment.type)
-          {
-          case SF_SLIDER:
-            script->arg_values[i].sfa_adjustment.adj = (GtkAdjustment *)
-              gimp_scale_entry_new (GTK_TABLE (sf_interface->table),
-                        0, row,
-                        label_text, SLIDER_WIDTH, -1,
-                        script->arg_values[i].sfa_adjustment.value,
-                        script->arg_defaults[i].sfa_adjustment.lower,
-                        script->arg_defaults[i].sfa_adjustment.upper,
-                        script->arg_defaults[i].sfa_adjustment.step,
-                        script->arg_defaults[i].sfa_adjustment.page,
-                        script->arg_defaults[i].sfa_adjustment.digits,
-                        TRUE, 0.0, 0.0,
-                        NULL, NULL);
-              gtk_entry_set_activates_default (GIMP_SCALE_ENTRY_SPINBUTTON 
(script->arg_values[i].sfa_adjustment.adj), TRUE);
-            break;
-
-          default:
-            g_warning ("unexpected adjustment type: %d",
-                       script->arg_defaults[i].sfa_adjustment.type);
-            /* fallthrough */
-
-          case SF_SPINNER:
-            left_align = TRUE;
-            widget =
-              gimp_spin_button_new (&adj,
-                                    script->arg_values[i].sfa_adjustment.value,
-                                    script->arg_defaults[i].sfa_adjustment.lower,
-                                    script->arg_defaults[i].sfa_adjustment.upper,
-                                    script->arg_defaults[i].sfa_adjustment.step,
-                                    script->arg_defaults[i].sfa_adjustment.page,
-                                    0, 0,
-                                    script->arg_defaults[i].sfa_adjustment.digits);
-            gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
-            script->arg_values[i].sfa_adjustment.adj = GTK_ADJUSTMENT (adj);
-            break;
+            label_yalign = 0.0;
           }
+          break;
 
-          g_signal_connect (script->arg_values[i].sfa_adjustment.adj,
+        case SF_ADJUSTMENT:
+          switch (arg->default_value.sfa_adjustment.type)
+            {
+            case SF_SLIDER:
+              arg->value.sfa_adjustment.adj = (GtkAdjustment *)
+                gimp_scale_entry_new (GTK_TABLE (sf_interface->table),
+                                      0, row,
+                                      label_text, SLIDER_WIDTH, -1,
+                                      arg->value.sfa_adjustment.value,
+                                      arg->default_value.sfa_adjustment.lower,
+                                      arg->default_value.sfa_adjustment.upper,
+                                      arg->default_value.sfa_adjustment.step,
+                                      arg->default_value.sfa_adjustment.page,
+                                      arg->default_value.sfa_adjustment.digits,
+                                      TRUE, 0.0, 0.0,
+                                      NULL, NULL);
+              gtk_entry_set_activates_default (GIMP_SCALE_ENTRY_SPINBUTTON (arg->value.sfa_adjustment.adj), 
TRUE);
+              break;
+
+            default:
+              g_warning ("unexpected adjustment type: %d",
+                         arg->default_value.sfa_adjustment.type);
+              /* fallthrough */
+
+            case SF_SPINNER:
+              left_align = TRUE;
+              widget =
+                gimp_spin_button_new (&adj,
+                                      arg->value.sfa_adjustment.value,
+                                      arg->default_value.sfa_adjustment.lower,
+                                      arg->default_value.sfa_adjustment.upper,
+                                      arg->default_value.sfa_adjustment.step,
+                                      arg->default_value.sfa_adjustment.page,
+                                      0, 0,
+                                      arg->default_value.sfa_adjustment.digits);
+              gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+              arg->value.sfa_adjustment.adj = GTK_ADJUSTMENT (adj);
+              break;
+            }
+
+          g_signal_connect (arg->value.sfa_adjustment.adj,
                             "value-changed",
                             G_CALLBACK (gimp_double_adjustment_update),
-                            &script->arg_values[i].sfa_adjustment.value);
-        break;
+                            &arg->value.sfa_adjustment.value);
+          break;
 
-      case SF_FILENAME:
-      case SF_DIRNAME:
-        if (script->arg_types[i] == SF_FILENAME)
-          widget = gtk_file_chooser_button_new (_("Script-Fu File Selection"),
-                                                GTK_FILE_CHOOSER_ACTION_OPEN);
+        case SF_FILENAME:
+        case SF_DIRNAME:
+          if (arg->type == SF_FILENAME)
+            widget = gtk_file_chooser_button_new (_("Tiny-Fu File Selection"),
+                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
           else
-            widget = gtk_file_chooser_button_new (_("Script-Fu Folder Selection"),
+            widget = gtk_file_chooser_button_new (_("Tiny-Fu Folder Selection"),
                                                   GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
-        if (script->arg_values[i].sfa_file.filename)
-          gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
-                                           script->arg_values[i].sfa_file.filename);
 
-        g_signal_connect (widget, "selection-changed",
-                          G_CALLBACK (script_fu_file_callback),
-                          &script->arg_values[i].sfa_file);
-        break;
+          if (arg->value.sfa_file.filename)
+            gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
+                                           arg->value.sfa_file.filename);
 
-      case SF_FONT:
-        widget = gimp_font_select_button_new (_("Script-Fu Font Selection"),
-                                              script->arg_values[i].sfa_font);
-        g_signal_connect_swapped (widget, "font-set",
-                                  G_CALLBACK (script_fu_font_callback),
-                                  &script->arg_values[i].sfa_font);
-        break;
+          g_signal_connect (widget, "selection-changed",
+                            G_CALLBACK (script_fu_file_callback),
+                            &arg->value.sfa_file);
+          break;
 
-      case SF_PALETTE:
-        widget = gimp_palette_select_button_new (_("Script-Fu Palette Selection"),
-                                                 script->arg_values[i].sfa_palette);
-        g_signal_connect_swapped (widget, "palette-set",
-                                  G_CALLBACK (script_fu_palette_callback),
-                                  &script->arg_values[i].sfa_palette);
-        break;
+        case SF_FONT:
+          widget = gimp_font_select_button_new (_("Tiny-Fu Font Selection"),
+                                                arg->value.sfa_font);
+          g_signal_connect_swapped (widget, "font-set",
+                                    G_CALLBACK (script_fu_font_callback),
+                                    &arg->value.sfa_font);
+          break;
 
-      case SF_PATTERN:
-        left_align = TRUE;
-        widget = gimp_pattern_select_button_new (_("Script-Fu Pattern Selection"),
-                                                 script->arg_values[i].sfa_pattern);
-        g_signal_connect_swapped (widget, "pattern-set",
-                                  G_CALLBACK (script_fu_pattern_callback),
-                                  &script->arg_values[i].sfa_pattern);
-        break;
+        case SF_PALETTE:
+          widget = gimp_palette_select_button_new (_("Tiny-Fu Palette Selection"),
+                                                   arg->value.sfa_palette);
+          g_signal_connect_swapped (widget, "palette-set",
+                                    G_CALLBACK (script_fu_palette_callback),
+                                    &arg->value.sfa_palette);
+          break;
 
-      case SF_GRADIENT:
-        left_align = TRUE;
-        widget = gimp_gradient_select_button_new (_("Script-Fu Gradient Selection"),
-                                                  script->arg_values[i].sfa_gradient);
-        g_signal_connect_swapped (widget, "gradient-set",
-                                  G_CALLBACK (script_fu_gradient_callback),
-                                  &script->arg_values[i].sfa_gradient);
-        break;
+        case SF_PATTERN:
+          left_align = TRUE;
+          widget = gimp_pattern_select_button_new (_("Tiny-Fu Pattern Selection"),
+                                                   arg->value.sfa_pattern);
+          g_signal_connect_swapped (widget, "pattern-set",
+                                    G_CALLBACK (script_fu_pattern_callback),
+                                    &arg->value.sfa_pattern);
+          break;
 
-      case SF_BRUSH:
-        left_align = TRUE;
-        widget = gimp_brush_select_button_new (_("Script-Fu Brush Selection"),
-                                               script->arg_values[i].sfa_brush.name,
-                                               script->arg_values[i].sfa_brush.opacity,
-                                               script->arg_values[i].sfa_brush.spacing,
-                                               script->arg_values[i].sfa_brush.paint_mode);
-        g_signal_connect_swapped (widget, "brush-set",
-                                  G_CALLBACK (script_fu_brush_callback),
-                                  &script->arg_values[i].sfa_brush);
-        break;
+        case SF_GRADIENT:
+          left_align = TRUE;
+          widget = gimp_gradient_select_button_new (_("Tiny-Fu Gradient Selection"),
+                                                    arg->value.sfa_gradient);
+          g_signal_connect_swapped (widget, "gradient-set",
+                                    G_CALLBACK (script_fu_gradient_callback),
+                                    &arg->value.sfa_gradient);
+          break;
 
-      case SF_OPTION:
-        widget = gtk_combo_box_new_text ();
-        for (list = script->arg_defaults[i].sfa_option.list;
-             list;
-             list = g_slist_next (list))
-          {
-            gtk_combo_box_append_text (GTK_COMBO_BOX (widget),
-                                       gettext ((const gchar *) list->data));
-          }
+        case SF_BRUSH:
+          left_align = TRUE;
+          widget = gimp_brush_select_button_new (_("Tiny-Fu Brush Selection"),
+                                                 arg->value.sfa_brush.name,
+                                                 arg->value.sfa_brush.opacity,
+                                                 arg->value.sfa_brush.spacing,
+                                                 arg->value.sfa_brush.paint_mode);
+          g_signal_connect_swapped (widget, "brush-set",
+                                    G_CALLBACK (script_fu_brush_callback),
+                                    &arg->value.sfa_brush);
+          break;
 
-        gtk_combo_box_set_active (GTK_COMBO_BOX (widget),
-                                  script->arg_values[i].sfa_option.history);
+        case SF_OPTION:
+          widget = gtk_combo_box_text_new ();
+          for (list = arg->default_value.sfa_option.list;
+               list;
+               list = g_slist_next (list))
+            {
+              gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget),
+                                              gettext (list->data));
+            }
 
-        g_signal_connect (widget, "changed",
-                          G_CALLBACK (script_fu_combo_callback),
-                          &script->arg_values[i].sfa_option);
-        break;
+          gtk_combo_box_set_active (GTK_COMBO_BOX (widget),
+                                    arg->value.sfa_option.history);
 
-      case SF_ENUM:
-        widget = gimp_enum_combo_box_new (g_type_from_name (script->arg_defaults[i].sfa_enum.type_name));
+          g_signal_connect (widget, "changed",
+                            G_CALLBACK (script_fu_combo_callback),
+                            &arg->value.sfa_option);
+          break;
 
-        gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget),
-                                       script->arg_values[i].sfa_enum.history);
+        case SF_ENUM:
+          widget = gimp_enum_combo_box_new (g_type_from_name (arg->default_value.sfa_enum.type_name));
 
-        g_signal_connect (widget, "changed",
-                          G_CALLBACK (gimp_int_combo_box_get_active),
-                          &script->arg_values[i].sfa_enum.history);
-        break;
+          gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget),
+                                         arg->value.sfa_enum.history);
 
-      case SF_DISPLAY:
-        break;
-      }
+          g_signal_connect (widget, "changed",
+                            G_CALLBACK (gimp_int_combo_box_get_active),
+                            &arg->value.sfa_enum.history);
+          break;
+
+        case SF_DISPLAY:
+          break;
+        }
 
       if (widget)
         {
@@ -578,7 +561,7 @@ script_fu_interface (SFScript *script,
   g_object_unref (group);
 
   /* the script progress bar */
-  vbox2 = gtk_vbox_new (FALSE, 6);
+  vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
   gtk_box_pack_end (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
   gtk_widget_show (vbox2);
 
@@ -601,6 +584,8 @@ script_fu_interface (SFScript *script,
   gtk_widget_show (dialog);
 
   gtk_main ();
+
+  return sf_status;
 }
 
 static void
@@ -613,8 +598,8 @@ script_fu_interface_quit (SFScript *script)
 
   g_free (sf_interface->title);
 
-  for (i = 0; i < script->num_args; i++)
-    switch (script->arg_types[i])
+  for (i = 0; i < script->n_args; i++)
+    switch (script->args[i].type)
       {
       case SF_FONT:
       case SF_PALETTE:
@@ -635,8 +620,7 @@ script_fu_interface_quit (SFScript *script)
   g_slice_free (SFInterface, sf_interface);
   sf_interface = NULL;
 
-  /*
-   *  We do not call gtk_main_quit() earlier to reduce the possibility
+  /*  We do not call gtk_main_quit() earlier to reduce the possibility
    *  that script_fu_script_proc() is called from gimp_extension_process()
    *  while we are not finished with the current script. This sucks!
    */
@@ -735,7 +719,11 @@ script_fu_response (GtkWidget *widget,
                     gint       response_id,
                     SFScript  *script)
 {
-  if (! GTK_WIDGET_SENSITIVE (GTK_DIALOG (sf_interface->dialog)->action_area))
+  GtkWidget *action_area;
+
+  action_area = gtk_dialog_get_action_area (GTK_DIALOG (sf_interface->dialog));
+
+  if (! gtk_widget_is_sensitive (action_area))
     return;
 
   switch (response_id)
@@ -746,13 +734,14 @@ script_fu_response (GtkWidget *widget,
 
     case GTK_RESPONSE_OK:
       gtk_widget_set_sensitive (sf_interface->table, FALSE);
-      gtk_widget_set_sensitive (GTK_DIALOG (sf_interface->dialog)->action_area,
-                                FALSE);
+      gtk_widget_set_sensitive (action_area, FALSE);
 
       script_fu_ok (script);
-      /* fallthru */
+      gtk_widget_destroy (sf_interface->dialog);
+      break;
 
     default:
+      sf_status = GIMP_PDB_CANCEL;
       gtk_widget_destroy (sf_interface->dialog);
       break;
     }
@@ -761,23 +750,16 @@ script_fu_response (GtkWidget *widget,
 static void
 script_fu_ok (SFScript *script)
 {
-  gchar   *escaped;
-  GString *s, *output;
+  GString *output;
   gchar   *command;
-  gchar    buffer[G_ASCII_DTOSTR_BUF_SIZE];
   gint     i;
 
-  s = g_string_new ("(");
-  g_string_append (s, script->name);
-
-  for (i = 0; i < script->num_args; i++)
+  for (i = 0; i < script->n_args; i++)
     {
-      SFArgValue *arg_value = &script->arg_values[i];
+      SFArgValue *arg_value = &script->args[i].value;
       GtkWidget  *widget    = sf_interface->widgets[i];
 
-      g_string_append_c (s, ' ');
-
-      switch (script->arg_types[i])
+      switch (script->args[i].type)
         {
         case SF_IMAGE:
         case SF_DRAWABLE:
@@ -785,39 +767,15 @@ script_fu_ok (SFScript *script)
         case SF_CHANNEL:
         case SF_VECTORS:
         case SF_DISPLAY:
-          g_string_append_printf (s, "%d", arg_value->sfa_image);
-          break;
-
         case SF_COLOR:
-          {
-            guchar r, g, b;
-
-            gimp_rgb_get_uchar (&arg_value->sfa_color, &r, &g, &b);
-            g_string_append_printf (s, "'(%d %d %d)",
-                                    (gint) r, (gint) g, (gint) b);
-          }
-          break;
-
         case SF_TOGGLE:
-          g_string_append (s, arg_value->sfa_toggle ? "TRUE" : "FALSE");
           break;
 
         case SF_VALUE:
-          g_free (arg_value->sfa_value);
-          arg_value->sfa_value =
-            g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
-
-          g_string_append (s, arg_value->sfa_value);
-          break;
-
         case SF_STRING:
           g_free (arg_value->sfa_value);
           arg_value->sfa_value =
             g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
-
-          escaped = script_fu_strescape (arg_value->sfa_value);
-          g_string_append_printf (s, "\"%s\"", escaped);
-          g_free (escaped);
           break;
 
         case SF_TEXT:
@@ -836,72 +794,42 @@ script_fu_ok (SFScript *script)
             arg_value->sfa_value = gtk_text_buffer_get_text (buffer,
                                                              &start, &end,
                                                              FALSE);
-
-            escaped = script_fu_strescape (arg_value->sfa_value);
-            g_string_append_printf (s, "\"%s\"", escaped);
-            g_free (escaped);
           }
           break;
 
         case SF_ADJUSTMENT:
-          g_ascii_dtostr (buffer, sizeof (buffer),
-                          arg_value->sfa_adjustment.value);
-          g_string_append (s, buffer);
-          break;
-
         case SF_FILENAME:
         case SF_DIRNAME:
-          escaped = script_fu_strescape (arg_value->sfa_file.filename);
-          g_string_append_printf (s, "\"%s\"", escaped);
-          g_free (escaped);
-          break;
-
         case SF_FONT:
-          g_string_append_printf (s, "\"%s\"", arg_value->sfa_font);
-          break;
-
         case SF_PALETTE:
-          g_string_append_printf (s, "\"%s\"", arg_value->sfa_palette);
-          break;
-
         case SF_PATTERN:
-          g_string_append_printf (s, "\"%s\"", arg_value->sfa_pattern);
-          break;
-
         case SF_GRADIENT:
-          g_string_append_printf (s, "\"%s\"", arg_value->sfa_gradient);
-          break;
-
         case SF_BRUSH:
-          g_ascii_dtostr (buffer, sizeof (buffer),
-                          arg_value->sfa_brush.opacity);
-
-          g_string_append_printf (s, "'(\"%s\" %s %d %d)",
-                                  arg_value->sfa_brush.name,
-                                  buffer,
-                                  arg_value->sfa_brush.spacing,
-                                  arg_value->sfa_brush.paint_mode);
-          break;
-
         case SF_OPTION:
-          g_string_append_printf (s, "%d", arg_value->sfa_option.history);
-          break;
-
         case SF_ENUM:
-          g_string_append_printf (s, "%d", arg_value->sfa_enum.history);
           break;
         }
     }
 
-  g_string_append_c (s, ')');
-
-  command = g_string_free (s, FALSE);
+  command = script_fu_script_get_command (script);
 
   /*  run the command through the interpreter  */
-  output = g_string_new ("");
+  output = g_string_new (NULL);
   ts_register_output_func (ts_gstring_output_func, output);
+
+  gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_PLUGIN);
+
   if (ts_interpret_string (command))
-    script_fu_error_msg (command, output->str);
+    {
+      gchar *message = g_strdup_printf (_("Error while executing %s:"),
+                                        script->name);
+
+      g_message ("%s\n\n%s", message, output->str);
+      g_free (message);
+    }
+
+  gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_INTERNAL);
+
   g_string_free (output, TRUE);
 
   g_free (command);
@@ -912,11 +840,14 @@ script_fu_reset (SFScript *script)
 {
   gint i;
 
-  for (i = 0; i < script->num_args; i++)
+  script_fu_script_reset (script, FALSE);
+
+  for (i = 0; i < script->n_args; i++)
     {
-      GtkWidget *widget = sf_interface->widgets[i];
+      SFArgValue *value  = &script->args[i].value;
+      GtkWidget  *widget = sf_interface->widgets[i];
 
-      switch (script->arg_types[i])
+      switch (script->args[i].type)
         {
         case SF_IMAGE:
         case SF_DRAWABLE:
@@ -928,18 +859,17 @@ script_fu_reset (SFScript *script)
 
         case SF_COLOR:
           gimp_color_button_set_color (GIMP_COLOR_BUTTON (widget),
-                                       &script->arg_defaults[i].sfa_color);
+                                       &value->sfa_color);
           break;
 
         case SF_TOGGLE:
           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
-                                        script->arg_defaults[i].sfa_toggle);
+                                        value->sfa_toggle);
           break;
 
         case SF_VALUE:
         case SF_STRING:
-          gtk_entry_set_text (GTK_ENTRY (widget),
-                              script->arg_defaults[i].sfa_value);
+          gtk_entry_set_text (GTK_ENTRY (widget), value->sfa_value);
           break;
 
         case SF_TEXT:
@@ -947,65 +877,60 @@ script_fu_reset (SFScript *script)
             GtkWidget     *view;
             GtkTextBuffer *buffer;
 
-            g_free (script->arg_values[i].sfa_value);
-            script->arg_values[i].sfa_value =
-              g_strdup (script->arg_defaults[i].sfa_value);
-
             view = gtk_bin_get_child (GTK_BIN (widget));
             buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
 
-            gtk_text_buffer_set_text (buffer,
-                                      script->arg_values[i].sfa_value, -1);
+            gtk_text_buffer_set_text (buffer, value->sfa_value, -1);
           }
           break;
 
         case SF_ADJUSTMENT:
-          gtk_adjustment_set_value (script->arg_values[i].sfa_adjustment.adj,
-                                    script->arg_defaults[i].sfa_adjustment.value);
+          gtk_adjustment_set_value (value->sfa_adjustment.adj,
+                                    value->sfa_adjustment.value);
           break;
 
         case SF_FILENAME:
         case SF_DIRNAME:
           gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
-                                         script->arg_defaults[i].sfa_file.filename);
+                                         value->sfa_file.filename);
           break;
 
         case SF_FONT:
           gimp_font_select_button_set_font (GIMP_FONT_SELECT_BUTTON (widget),
-                                            script->arg_defaults[i].sfa_font);
+                                            value->sfa_font);
           break;
 
         case SF_PALETTE:
           gimp_palette_select_button_set_palette (GIMP_PALETTE_SELECT_BUTTON (widget),
-                                                  script->arg_defaults[i].sfa_palette);
+                                                  value->sfa_palette);
           break;
 
         case SF_PATTERN:
           gimp_pattern_select_button_set_pattern (GIMP_PATTERN_SELECT_BUTTON (widget),
-                                                  script->arg_defaults[i].sfa_pattern);
+                                                  value->sfa_pattern);
           break;
 
         case SF_GRADIENT:
           gimp_gradient_select_button_set_gradient (GIMP_GRADIENT_SELECT_BUTTON (widget),
-                                                    script->arg_defaults[i].sfa_gradient);
+                                                    value->sfa_gradient);
           break;
 
         case SF_BRUSH:
           gimp_brush_select_button_set_brush (GIMP_BRUSH_SELECT_BUTTON (widget),
-                                              script->arg_defaults[i].sfa_brush.name,
-                                              script->arg_defaults[i].sfa_brush.opacity,
-                                              script->arg_defaults[i].sfa_brush.spacing,
-                                              script->arg_defaults[i].sfa_brush.paint_mode);
+                                              value->sfa_brush.name,
+                                              value->sfa_brush.opacity,
+                                              value->sfa_brush.spacing,
+                                              value->sfa_brush.paint_mode);
           break;
 
         case SF_OPTION:
           gtk_combo_box_set_active (GTK_COMBO_BOX (widget),
-                                    script->arg_defaults[i].sfa_option.history);
+                                    value->sfa_option.history);
           break;
 
         case SF_ENUM:
           gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget),
-                                         script->arg_defaults[i].sfa_enum.history);
+                                         value->sfa_enum.history);
           break;
         }
     }
diff --git a/tiny-fu/tiny-fu-interface.h b/tiny-fu/tiny-fu-interface.h
index 11bd7b0..d1b9fbc 100644
--- a/tiny-fu/tiny-fu-interface.h
+++ b/tiny-fu/tiny-fu-interface.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,18 +12,17 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_INTERFACE_H__
 #define __SCRIPT_FU_INTERFACE_H__
 
 
-void       script_fu_interface           (SFScript    *script,
-                                          gint         start_arg);
-void       script_fu_interface_report_cc (const gchar *command);
-gboolean   script_fu_interface_is_active (void);
+GimpPDBStatusType  script_fu_interface           (SFScript     *script,
+                                                  gint          start_arg);
+void               script_fu_interface_report_cc (const gchar  *command);
+gboolean           script_fu_interface_is_active (void);
 
 
 #endif /*  __SCRIPT_FU_INTERFACE_H__  */
diff --git a/tiny-fu/tiny-fu-intl.h b/tiny-fu/tiny-fu-intl.h
index 58f09cc..5625005 100644
--- a/tiny-fu/tiny-fu-intl.h
+++ b/tiny-fu/tiny-fu-intl.h
@@ -1,12 +1,12 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * script-fu-intl.h
+ * tiny-fu-intl.h
  *
- * This library is free software; you can redistribute it and/or
+ * This library is free software: you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 3 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,38 +14,29 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_INTL_H__
 #define __SCRIPT_FU_INTL_H__
 
 #ifndef GETTEXT_PACKAGE
-#error "config.h must be included prior to script-fu-intl.h"
+#error "config.h must be included prior to tiny-fu-intl.h"
 #endif
 
-#include <libintl.h>
+#include <glib/gi18n.h>
 
 
-#define _(String) gettext (String)
-
-#ifdef gettext_noop
-#    define N_(String) gettext_noop (String)
-#else
-#    define N_(String) (String)
-#endif
-
 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
 #    define bind_textdomain_codeset(Domain, Codeset) (Domain)
 #endif
 
 #define INIT_I18N()    G_STMT_START{                             \
-  bindtextdomain (GETTEXT_PACKAGE"-script-fu",                    \
+  bindtextdomain (GETTEXT_PACKAGE"-tiny-fu",                    \
                   gimp_locale_directory ());                      \
-  bind_textdomain_codeset (GETTEXT_PACKAGE"-script-fu", "UTF-8"); \
-  textdomain (GETTEXT_PACKAGE"-script-fu");                       \
+  bind_textdomain_codeset (GETTEXT_PACKAGE"-tiny-fu", "UTF-8"); \
+  textdomain (GETTEXT_PACKAGE"-tiny-fu");                       \
 }G_STMT_END
 
 
diff --git a/tiny-fu/tiny-fu-regex.c b/tiny-fu/tiny-fu-regex.c
new file mode 100644
index 0000000..30aea36
--- /dev/null
+++ b/tiny-fu/tiny-fu-regex.c
@@ -0,0 +1,170 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* Based on re.c
+ *
+ * Henry Spencer's implementation of Regular Expressions,
+ * used for TinyScheme
+ *
+ * Refurbished by Stephen Gildea
+ *
+ * Ported to GRegex and de-uglified by Michael Natterer
+ */
+
+#include "config.h"
+
+#include "tinyscheme/scheme-private.h"
+#include "tiny-fu-regex.h"
+
+
+/*  local function prototypes  */
+
+static pointer foreign_re_match (scheme  *sc,
+                                 pointer  args);
+static void    set_vector_elem  (pointer  vec,
+                                 int      ielem,
+                                 pointer  newel);
+
+
+/*  public functions  */
+
+void
+script_fu_regex_init (scheme *sc)
+{
+  sc->vptr->scheme_define (sc,
+                           sc->global_env,
+                           sc->vptr->mk_symbol(sc,"re-match"),
+                           sc->vptr->mk_foreign_func(sc, foreign_re_match));
+
+#if 0
+  sc->vptr->load_string
+    (sc,
+     ";; return the substring of STRING matched in MATCH-VECTOR,\n"
+     ";; the Nth subexpression match (default 0).\n"
+     "\n"
+     "(define (re-match-nth string match-vector . n)\n"
+     "  (let ((n (if (pair? n) (car n) 0)))\n"
+     "    (substring string (car (vector-ref match-vector n))\n"
+     "                      (cdr (vector-ref match-vector n)))))\n"
+     "(define (re-before-nth string match-vector . n)\n"
+     "  (let ((n (if (pair? n) (car n) 0)))\n"
+     "    (substring string 0 (car (vector-ref match-vector n)))))\n"
+     "(define (re-after-nth string match-vector . n)\n"
+     "  (let ((n (if (pair? n) (car n) 0)))\n"
+     "    (substring string (cdr (vector-ref match-vector n))\n"
+     "                      (string-length string))))\n");
+#endif
+}
+
+
+/*  private functions  */
+
+static pointer
+foreign_re_match (scheme  *sc,
+                  pointer  args)
+{
+  pointer   retval = sc->F;
+  gboolean  success;
+  GRegex   *regex;
+  pointer   first_arg, second_arg;
+  pointer   third_arg = sc->NIL;
+  char     *string;
+  char     *pattern;
+  int       num = 0;
+
+  if (!((args != sc->NIL)
+        && sc->vptr->is_string ((first_arg = sc->vptr->pair_car (args)))
+        && (args = sc->vptr->pair_cdr (args))
+        && sc->vptr->is_pair (args)
+        && sc->vptr->is_string ((second_arg = sc->vptr->pair_car (args)))))
+    {
+      return sc->F;
+    }
+
+  pattern = sc->vptr->string_value (first_arg);
+  string  = sc->vptr->string_value (second_arg);
+
+  args = sc->vptr->pair_cdr (args);
+
+  if (args != sc->NIL)
+    {
+      if (!(sc->vptr->is_pair (args)
+            && sc->vptr->is_vector ((third_arg = sc->vptr->pair_car (args)))))
+        {
+          return sc->F;
+        }
+      else
+        {
+          num = third_arg->_object._number.value.ivalue;
+        }
+    }
+
+  regex = g_regex_new (pattern, G_REGEX_EXTENDED, 0, NULL);
+  if (! regex)
+    return sc->F;
+
+  if (! num)
+    {
+      success = g_regex_match (regex, string, 0, NULL);
+    }
+  else
+    {
+      GMatchInfo *match_info;
+      gint        i;
+
+      success = g_regex_match (regex, string, 0, &match_info);
+
+      for (i = 0; i < num; i++)
+        {
+          gint start, end;
+
+          g_match_info_fetch_pos (match_info, i, &start, &end);
+
+#undef cons
+          set_vector_elem (third_arg, i,
+                           sc->vptr->cons(sc,
+                                          sc->vptr->mk_integer(sc, start),
+                                          sc->vptr->mk_integer(sc, end)));
+        }
+
+      g_match_info_free (match_info);
+    }
+
+  if (success)
+    retval = sc->T;
+
+  g_regex_unref (regex);
+
+  return retval;
+}
+
+static void
+set_vector_elem (pointer vec,
+                 int     ielem,
+                 pointer newel)
+{
+  int n = ielem / 2;
+
+  if (ielem % 2 == 0)
+    {
+      vec[1 + n]._object._cons._car = newel;
+    }
+  else
+    {
+      vec[1 + n]._object._cons._cdr = newel;
+    }
+}
diff --git a/tiny-fu/tiny-fu-regex.h b/tiny-fu/tiny-fu-regex.h
new file mode 100644
index 0000000..e8786b1
--- /dev/null
+++ b/tiny-fu/tiny-fu-regex.h
@@ -0,0 +1,25 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_REGEX_H__
+#define __SCRIPT_FU_REGEX_H__
+
+
+void   script_fu_regex_init (scheme *sc);
+
+
+#endif /* __SCRIPT_FU_REGEX_H__ */
diff --git a/tiny-fu/tiny-fu-script.c b/tiny-fu/tiny-fu-script.c
new file mode 100644
index 0000000..eb60f69
--- /dev/null
+++ b/tiny-fu/tiny-fu-script.c
@@ -0,0 +1,780 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "tinyscheme/scheme-private.h"
+
+#include "tiny-fu-types.h"
+
+#include "tiny-fu-script.h"
+#include "tiny-fu-scripts.h"
+#include "tiny-fu-utils.h"
+
+#include "tiny-fu-intl.h"
+
+
+/*
+ *  Local Functions
+ */
+
+static gboolean   script_fu_script_param_init (SFScript        *script,
+                                               gint             nparams,
+                                               const GimpParam *params,
+                                               SFArgType        type,
+                                               gint             n);
+
+
+/*
+ *  Function definitions
+ */
+
+SFScript *
+script_fu_script_new (const gchar *name,
+                      const gchar *menu_label,
+                      const gchar *blurb,
+                      const gchar *author,
+                      const gchar *copyright,
+                      const gchar *date,
+                      const gchar *image_types,
+                      gint         n_args)
+{
+  SFScript *script;
+
+  script = g_slice_new0 (SFScript);
+
+  script->name        = g_strdup (name);
+  script->menu_label  = g_strdup (menu_label);
+  script->blurb       = g_strdup (blurb);
+  script->author      = g_strdup (author);
+  script->copyright   = g_strdup (copyright);
+  script->date        = g_strdup (date);
+  script->image_types = g_strdup (image_types);
+
+  script->n_args = n_args;
+  script->args   = g_new0 (SFArg, script->n_args);
+
+  return script;
+}
+
+void
+script_fu_script_free (SFScript *script)
+{
+  gint i;
+
+  g_return_if_fail (script != NULL);
+
+  g_free (script->name);
+  g_free (script->blurb);
+  g_free (script->menu_label);
+  g_free (script->author);
+  g_free (script->copyright);
+  g_free (script->date);
+  g_free (script->image_types);
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      SFArg *arg = &script->args[i];
+
+      g_free (arg->label);
+
+      switch (arg->type)
+        {
+        case SF_IMAGE:
+        case SF_DRAWABLE:
+        case SF_LAYER:
+        case SF_CHANNEL:
+        case SF_VECTORS:
+        case SF_DISPLAY:
+        case SF_COLOR:
+        case SF_TOGGLE:
+          break;
+
+        case SF_VALUE:
+        case SF_STRING:
+        case SF_TEXT:
+          g_free (arg->default_value.sfa_value);
+          g_free (arg->value.sfa_value);
+          break;
+
+        case SF_ADJUSTMENT:
+          break;
+
+        case SF_FILENAME:
+        case SF_DIRNAME:
+          g_free (arg->default_value.sfa_file.filename);
+          g_free (arg->value.sfa_file.filename);
+          break;
+
+        case SF_FONT:
+          g_free (arg->default_value.sfa_font);
+          g_free (arg->value.sfa_font);
+          break;
+
+        case SF_PALETTE:
+          g_free (arg->default_value.sfa_palette);
+          g_free (arg->value.sfa_palette);
+          break;
+
+        case SF_PATTERN:
+          g_free (arg->default_value.sfa_pattern);
+          g_free (arg->value.sfa_pattern);
+          break;
+
+        case SF_GRADIENT:
+          g_free (arg->default_value.sfa_gradient);
+          g_free (arg->value.sfa_gradient);
+          break;
+
+        case SF_BRUSH:
+          g_free (arg->default_value.sfa_brush.name);
+          g_free (arg->value.sfa_brush.name);
+          break;
+
+        case SF_OPTION:
+          g_slist_free_full (arg->default_value.sfa_option.list,
+                             (GDestroyNotify) g_free);
+          break;
+
+        case SF_ENUM:
+          g_free (arg->default_value.sfa_enum.type_name);
+          break;
+        }
+    }
+
+  g_free (script->args);
+
+  g_slice_free (SFScript, script);
+}
+
+void
+script_fu_script_install_proc (SFScript    *script,
+                               GimpRunProc  run_proc)
+{
+  const gchar  *menu_label = NULL;
+  GimpParamDef *args;
+  gint          i;
+
+  g_return_if_fail (script != NULL);
+  g_return_if_fail (run_proc != NULL);
+
+  /* Allow scripts with no menus */
+  if (strncmp (script->menu_label, "<None>", 6) != 0)
+    menu_label = script->menu_label;
+
+  args = g_new0 (GimpParamDef, script->n_args + 1);
+
+  args[0].type        = GIMP_PDB_INT32;
+  args[0].name        = "run-mode";
+  args[0].description = "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }";
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      GimpPDBArgType  type = 0;
+      const gchar    *name = NULL;
+
+      switch (script->args[i].type)
+        {
+        case SF_IMAGE:
+          type = GIMP_PDB_IMAGE;
+          name = "image";
+          break;
+
+        case SF_DRAWABLE:
+          type = GIMP_PDB_DRAWABLE;
+          name = "drawable";
+          break;
+
+        case SF_LAYER:
+          type = GIMP_PDB_LAYER;
+          name = "layer";
+          break;
+
+        case SF_CHANNEL:
+          type = GIMP_PDB_CHANNEL;
+          name = "channel";
+          break;
+
+        case SF_VECTORS:
+          type = GIMP_PDB_VECTORS;
+          name = "vectors";
+          break;
+
+        case SF_DISPLAY:
+          type = GIMP_PDB_DISPLAY;
+          name = "display";
+          break;
+
+        case SF_COLOR:
+          type = GIMP_PDB_COLOR;
+          name = "color";
+          break;
+
+        case SF_TOGGLE:
+          type = GIMP_PDB_INT32;
+          name = "toggle";
+          break;
+
+        case SF_VALUE:
+          type = GIMP_PDB_STRING;
+          name = "value";
+          break;
+
+        case SF_STRING:
+        case SF_TEXT:
+          type = GIMP_PDB_STRING;
+          name = "string";
+          break;
+
+        case SF_ADJUSTMENT:
+          type = GIMP_PDB_FLOAT;
+          name = "value";
+          break;
+
+        case SF_FILENAME:
+          type = GIMP_PDB_STRING;
+          name = "filename";
+          break;
+
+        case SF_DIRNAME:
+          type = GIMP_PDB_STRING;
+          name = "dirname";
+          break;
+
+        case SF_FONT:
+          type = GIMP_PDB_STRING;
+          name = "font";
+          break;
+
+        case SF_PALETTE:
+          type = GIMP_PDB_STRING;
+          name = "palette";
+          break;
+
+        case SF_PATTERN:
+          type = GIMP_PDB_STRING;
+          name = "pattern";
+          break;
+
+        case SF_BRUSH:
+          type = GIMP_PDB_STRING;
+          name = "brush";
+          break;
+
+        case SF_GRADIENT:
+          type = GIMP_PDB_STRING;
+          name = "gradient";
+          break;
+
+        case SF_OPTION:
+          type = GIMP_PDB_INT32;
+          name = "option";
+          break;
+
+        case SF_ENUM:
+          type = GIMP_PDB_INT32;
+          name = "enum";
+          break;
+        }
+
+      args[i + 1].type        = type;
+      args[i + 1].name        = (gchar *) name;
+      args[i + 1].description = script->args[i].label;
+    }
+
+  gimp_install_temp_proc (script->name,
+                          script->blurb,
+                          "",
+                          script->author,
+                          script->copyright,
+                          script->date,
+                          menu_label,
+                          script->image_types,
+                          GIMP_TEMPORARY,
+                          script->n_args + 1, 0,
+                          args, NULL,
+                          run_proc);
+
+  g_free (args);
+}
+
+void
+script_fu_script_uninstall_proc (SFScript *script)
+{
+  g_return_if_fail (script != NULL);
+
+  gimp_uninstall_temp_proc (script->name);
+}
+
+gchar *
+script_fu_script_get_title (SFScript *script)
+{
+  gchar *title;
+  gchar *tmp;
+
+  g_return_val_if_fail (script != NULL, NULL);
+
+  /* strip mnemonics from the menupath */
+  title = gimp_strip_uline (gettext (script->menu_label));
+
+  /* if this looks like a full menu path, use only the last part */
+  if (title[0] == '<' && (tmp = strrchr (title, '/')) && tmp[1])
+    {
+      tmp = g_strdup (tmp + 1);
+
+      g_free (title);
+      title = tmp;
+    }
+
+  /* cut off ellipsis */
+  tmp = (strstr (title, "..."));
+  if (! tmp)
+    /* U+2026 HORIZONTAL ELLIPSIS */
+    tmp = strstr (title, "\342\200\246");
+
+  if (tmp && tmp == (title + strlen (title) - 3))
+    *tmp = '\0';
+
+  return title;
+}
+
+void
+script_fu_script_reset (SFScript *script,
+                        gboolean  reset_ids)
+{
+  gint i;
+
+  g_return_if_fail (script != NULL);
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      SFArgValue *value         = &script->args[i].value;
+      SFArgValue *default_value = &script->args[i].default_value;
+
+      switch (script->args[i].type)
+        {
+        case SF_IMAGE:
+        case SF_DRAWABLE:
+        case SF_LAYER:
+        case SF_CHANNEL:
+        case SF_VECTORS:
+        case SF_DISPLAY:
+          if (reset_ids)
+            value->sfa_image = default_value->sfa_image;
+          break;
+
+        case SF_COLOR:
+          value->sfa_color = default_value->sfa_color;
+          break;
+
+        case SF_TOGGLE:
+          value->sfa_toggle = default_value->sfa_toggle;
+          break;
+
+        case SF_VALUE:
+        case SF_STRING:
+        case SF_TEXT:
+          g_free (value->sfa_value);
+          value->sfa_value = g_strdup (default_value->sfa_value);
+          break;
+
+        case SF_ADJUSTMENT:
+          value->sfa_adjustment.value = default_value->sfa_adjustment.value;
+          break;
+
+        case SF_FILENAME:
+        case SF_DIRNAME:
+          g_free (value->sfa_file.filename);
+          value->sfa_file.filename = g_strdup (default_value->sfa_file.filename);
+          break;
+
+        case SF_FONT:
+          g_free (value->sfa_font);
+          value->sfa_font = g_strdup (default_value->sfa_font);
+          break;
+
+        case SF_PALETTE:
+          g_free (value->sfa_palette);
+          value->sfa_palette = g_strdup (default_value->sfa_palette);
+          break;
+
+        case SF_PATTERN:
+          g_free (value->sfa_pattern);
+          value->sfa_pattern = g_strdup (default_value->sfa_pattern);
+          break;
+
+        case SF_GRADIENT:
+          g_free (value->sfa_gradient);
+          value->sfa_gradient = g_strdup (default_value->sfa_gradient);
+          break;
+
+        case SF_BRUSH:
+          g_free (value->sfa_brush.name);
+          value->sfa_brush.name = g_strdup (default_value->sfa_brush.name);
+          value->sfa_brush.opacity    = default_value->sfa_brush.opacity;
+          value->sfa_brush.spacing    = default_value->sfa_brush.spacing;
+          value->sfa_brush.paint_mode = default_value->sfa_brush.paint_mode;
+          break;
+
+        case SF_OPTION:
+          value->sfa_option.history = default_value->sfa_option.history;
+          break;
+
+        case SF_ENUM:
+          value->sfa_enum.history = default_value->sfa_enum.history;
+          break;
+        }
+    }
+}
+
+gint
+script_fu_script_collect_standard_args (SFScript        *script,
+                                        gint             n_params,
+                                        const GimpParam *params)
+{
+  gint params_consumed = 0;
+
+  g_return_val_if_fail (script != NULL, 0);
+
+  /*  the first parameter may be a DISPLAY id  */
+  if (script_fu_script_param_init (script,
+                                   n_params, params, SF_DISPLAY,
+                                   params_consumed))
+    {
+      params_consumed++;
+    }
+
+  /*  an IMAGE id may come first or after the DISPLAY id  */
+  if (script_fu_script_param_init (script,
+                                   n_params, params, SF_IMAGE,
+                                   params_consumed))
+    {
+      params_consumed++;
+
+      /*  and may be followed by a DRAWABLE, LAYER, CHANNEL or
+       *  VECTORS id
+       */
+      if (script_fu_script_param_init (script,
+                                       n_params, params, SF_DRAWABLE,
+                                       params_consumed) ||
+          script_fu_script_param_init (script,
+                                       n_params, params, SF_LAYER,
+                                       params_consumed) ||
+          script_fu_script_param_init (script,
+                                       n_params, params, SF_CHANNEL,
+                                       params_consumed) ||
+          script_fu_script_param_init (script,
+                                       n_params, params, SF_VECTORS,
+                                       params_consumed))
+        {
+          params_consumed++;
+        }
+    }
+
+  return params_consumed;
+}
+
+gchar *
+script_fu_script_get_command (SFScript *script)
+{
+  GString *s;
+  gint     i;
+
+  g_return_val_if_fail (script != NULL, NULL);
+
+  s = g_string_new ("(");
+  g_string_append (s, script->name);
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      SFArgValue *arg_value = &script->args[i].value;
+
+      g_string_append_c (s, ' ');
+
+      switch (script->args[i].type)
+        {
+        case SF_IMAGE:
+        case SF_DRAWABLE:
+        case SF_LAYER:
+        case SF_CHANNEL:
+        case SF_VECTORS:
+        case SF_DISPLAY:
+          g_string_append_printf (s, "%d", arg_value->sfa_image);
+          break;
+
+        case SF_COLOR:
+          {
+            guchar r, g, b;
+
+            gimp_rgb_get_uchar (&arg_value->sfa_color, &r, &g, &b);
+            g_string_append_printf (s, "'(%d %d %d)",
+                                    (gint) r, (gint) g, (gint) b);
+          }
+          break;
+
+        case SF_TOGGLE:
+          g_string_append (s, arg_value->sfa_toggle ? "TRUE" : "FALSE");
+          break;
+
+        case SF_VALUE:
+          g_string_append (s, arg_value->sfa_value);
+          break;
+
+        case SF_STRING:
+        case SF_TEXT:
+          {
+            gchar *tmp;
+
+            tmp = script_fu_strescape (arg_value->sfa_value);
+            g_string_append_printf (s, "\"%s\"", tmp);
+            g_free (tmp);
+          }
+          break;
+
+        case SF_ADJUSTMENT:
+          {
+            gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+
+            g_ascii_dtostr (buffer, sizeof (buffer),
+                            arg_value->sfa_adjustment.value);
+            g_string_append (s, buffer);
+          }
+          break;
+
+        case SF_FILENAME:
+        case SF_DIRNAME:
+          {
+            gchar *tmp;
+
+            tmp = script_fu_strescape (arg_value->sfa_file.filename);
+            g_string_append_printf (s, "\"%s\"", tmp);
+            g_free (tmp);
+          }
+          break;
+
+        case SF_FONT:
+          g_string_append_printf (s, "\"%s\"", arg_value->sfa_font);
+          break;
+
+        case SF_PALETTE:
+          g_string_append_printf (s, "\"%s\"", arg_value->sfa_palette);
+          break;
+
+        case SF_PATTERN:
+          g_string_append_printf (s, "\"%s\"", arg_value->sfa_pattern);
+          break;
+
+        case SF_GRADIENT:
+          g_string_append_printf (s, "\"%s\"", arg_value->sfa_gradient);
+          break;
+
+        case SF_BRUSH:
+          {
+            gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+
+            g_ascii_dtostr (buffer, sizeof (buffer),
+                            arg_value->sfa_brush.opacity);
+            g_string_append_printf (s, "'(\"%s\" %s %d %d)",
+                                    arg_value->sfa_brush.name,
+                                    buffer,
+                                    arg_value->sfa_brush.spacing,
+                                    arg_value->sfa_brush.paint_mode);
+          }
+          break;
+
+        case SF_OPTION:
+          g_string_append_printf (s, "%d", arg_value->sfa_option.history);
+          break;
+
+        case SF_ENUM:
+          g_string_append_printf (s, "%d", arg_value->sfa_enum.history);
+          break;
+        }
+    }
+
+  g_string_append_c (s, ')');
+
+  return g_string_free (s, FALSE);
+}
+
+gchar *
+script_fu_script_get_command_from_params (SFScript        *script,
+                                          const GimpParam *params)
+{
+  GString *s;
+  gint     i;
+
+  g_return_val_if_fail (script != NULL, NULL);
+
+  s = g_string_new ("(");
+  g_string_append (s, script->name);
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      const GimpParam *param = &params[i + 1];
+
+      g_string_append_c (s, ' ');
+
+      switch (script->args[i].type)
+        {
+        case SF_IMAGE:
+        case SF_DRAWABLE:
+        case SF_LAYER:
+        case SF_CHANNEL:
+        case SF_VECTORS:
+        case SF_DISPLAY:
+          g_string_append_printf (s, "%d", param->data.d_int32);
+          break;
+
+        case SF_COLOR:
+          {
+            guchar r, g, b;
+
+            gimp_rgb_get_uchar (&param->data.d_color, &r, &g, &b);
+            g_string_append_printf (s, "'(%d %d %d)",
+                                    (gint) r, (gint) g, (gint) b);
+          }
+          break;
+
+        case SF_TOGGLE:
+          g_string_append_printf (s, (param->data.d_int32 ? "TRUE" : "FALSE"));
+          break;
+
+        case SF_VALUE:
+          g_string_append (s, param->data.d_string);
+          break;
+
+        case SF_STRING:
+        case SF_TEXT:
+        case SF_FILENAME:
+        case SF_DIRNAME:
+          {
+            gchar *tmp;
+
+            tmp = script_fu_strescape (param->data.d_string);
+            g_string_append_printf (s, "\"%s\"", tmp);
+            g_free (tmp);
+          }
+          break;
+
+        case SF_ADJUSTMENT:
+          {
+            gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
+
+            g_ascii_dtostr (buffer, sizeof (buffer), param->data.d_float);
+            g_string_append (s, buffer);
+          }
+          break;
+
+        case SF_FONT:
+        case SF_PALETTE:
+        case SF_PATTERN:
+        case SF_GRADIENT:
+        case SF_BRUSH:
+          g_string_append_printf (s, "\"%s\"", param->data.d_string);
+          break;
+
+        case SF_OPTION:
+        case SF_ENUM:
+          g_string_append_printf (s, "%d", param->data.d_int32);
+          break;
+        }
+    }
+
+  g_string_append_c (s, ')');
+
+  return g_string_free (s, FALSE);
+}
+
+
+/*
+ *  Local Functions
+ */
+
+static gboolean
+script_fu_script_param_init (SFScript        *script,
+                             gint             nparams,
+                             const GimpParam *params,
+                             SFArgType        type,
+                             gint             n)
+{
+  SFArg *arg = &script->args[n];
+
+  if (script->n_args > n && arg->type == type && nparams > n + 1)
+    {
+      switch (type)
+        {
+        case SF_IMAGE:
+          if (params[n + 1].type == GIMP_PDB_IMAGE)
+            {
+              arg->value.sfa_image = params[n + 1].data.d_image;
+              return TRUE;
+            }
+          break;
+
+        case SF_DRAWABLE:
+          if (params[n + 1].type == GIMP_PDB_DRAWABLE)
+            {
+              arg->value.sfa_drawable = params[n + 1].data.d_drawable;
+              return TRUE;
+            }
+          break;
+
+        case SF_LAYER:
+          if (params[n + 1].type == GIMP_PDB_LAYER)
+            {
+              arg->value.sfa_layer = params[n + 1].data.d_layer;
+              return TRUE;
+            }
+          break;
+
+        case SF_CHANNEL:
+          if (params[n + 1].type == GIMP_PDB_CHANNEL)
+            {
+              arg->value.sfa_channel = params[n + 1].data.d_channel;
+              return TRUE;
+            }
+          break;
+
+        case SF_VECTORS:
+          if (params[n + 1].type == GIMP_PDB_VECTORS)
+            {
+              arg->value.sfa_vectors = params[n + 1].data.d_vectors;
+              return TRUE;
+            }
+          break;
+
+        case SF_DISPLAY:
+          if (params[n + 1].type == GIMP_PDB_DISPLAY)
+            {
+              arg->value.sfa_display = params[n + 1].data.d_display;
+              return TRUE;
+            }
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  return FALSE;
+}
diff --git a/tiny-fu/tiny-fu-script.h b/tiny-fu/tiny-fu-script.h
new file mode 100644
index 0000000..c6d14dc
--- /dev/null
+++ b/tiny-fu/tiny-fu-script.h
@@ -0,0 +1,49 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_SCRIPT_H__
+#define __SCRIPT_FU_SCRIPT_H__
+
+
+SFScript * script_fu_script_new                     (const gchar     *name,
+                                                     const gchar     *menu_label,
+                                                     const gchar     *blurb,
+                                                     const gchar     *author,
+                                                     const gchar     *copyright,
+                                                     const gchar     *date,
+                                                     const gchar     *image_types,
+                                                     gint             n_args);
+void       script_fu_script_free                    (SFScript        *script);
+
+void       script_fu_script_install_proc            (SFScript        *script,
+                                                     GimpRunProc      run_proc);
+void       script_fu_script_uninstall_proc          (SFScript        *script);
+
+gchar    * script_fu_script_get_title               (SFScript        *script);
+void       script_fu_script_reset                   (SFScript        *script,
+                                                     gboolean         reset_ids);
+
+gint       script_fu_script_collect_standard_args   (SFScript        *script,
+                                                     gint             n_params,
+                                                     const GimpParam *params);
+
+gchar    * script_fu_script_get_command             (SFScript        *script);
+gchar    * script_fu_script_get_command_from_params (SFScript        *script,
+                                                     const GimpParam *params);
+
+
+#endif /*  __SCRIPT_FU_SCRIPT__  */
diff --git a/tiny-fu/tiny-fu-scripts.c b/tiny-fu/tiny-fu-scripts.c
index cb9a5d9..bdd4fe3 100644
--- a/tiny-fu/tiny-fu-scripts.c
+++ b/tiny-fu/tiny-fu-scripts.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -37,7 +36,9 @@
 #include "tiny-fu-types.h"
 
 #include "tiny-fu-interface.h"
+#include "tiny-fu-script.h"
 #include "tiny-fu-scripts.h"
+#include "tiny-fu-utils.h"
 
 #include "tiny-fu-intl.h"
 
@@ -53,27 +54,28 @@ typedef struct
  *  Local Functions
  */
 
-static void      script_fu_load_script    (const GimpDatafileData *file_data,
-                                           gpointer                user_data);
-static gboolean  script_fu_install_script (gpointer                foo,
-                                           GList                  *scripts,
-                                           gpointer                bar);
-static void      script_fu_install_menu   (SFMenu                 *menu);
-static gboolean  script_fu_remove_script  (gpointer                foo,
-                                           GList                  *scripts,
-                                           gpointer                bar);
-static void      script_fu_script_proc    (const gchar            *name,
-                                           gint                    nparams,
-                                           const GimpParam        *params,
-                                           gint                   *nreturn_vals,
-                                           GimpParam             **return_vals);
-
-static SFScript *script_fu_find_script    (const gchar            *name);
-static void      script_fu_free_script    (SFScript               *script);
-
-static void      script_fu_menu_map       (SFScript               *script);
-static gint      script_fu_menu_compare   (gconstpointer           a,
-                                           gconstpointer           b);
+static gboolean  script_fu_run_command    (const gchar             *command,
+                                           GError                 **error);
+static void      script_fu_load_script    (const GimpDatafileData  *file_data,
+                                           gpointer                 user_data);
+static gboolean  script_fu_install_script (gpointer                 foo,
+                                           GList                   *scripts,
+                                           gpointer                 bar);
+static void      script_fu_install_menu   (SFMenu                  *menu);
+static gboolean  script_fu_remove_script  (gpointer                 foo,
+                                           GList                   *scripts,
+                                           gpointer                 bar);
+static void      script_fu_script_proc    (const gchar             *name,
+                                           gint                     nparams,
+                                           const GimpParam         *params,
+                                           gint                    *nreturn_vals,
+                                           GimpParam              **return_vals);
+
+static SFScript *script_fu_find_script    (const gchar             *name);
+
+static gchar *   script_fu_menu_map       (const gchar             *menu_path);
+static gint      script_fu_menu_compare   (gconstpointer            a,
+                                           gconstpointer            b);
 
 
 /*
@@ -117,496 +119,394 @@ script_fu_find_scripts (const gchar *path)
   script_menu_list = g_list_sort (script_menu_list,
                                   (GCompareFunc) script_fu_menu_compare);
 
-  g_list_foreach (script_menu_list,
-                  (GFunc) script_fu_install_menu,
-                  NULL);
-
-  /*  Now we are done with the list of menu entries  */
-  g_list_free (script_menu_list);
+  /*  Install and nuke the list of menu entries  */
+  g_list_free_full (script_menu_list,
+                    (GDestroyNotify) script_fu_install_menu);
   script_menu_list = NULL;
 }
 
 pointer
-script_fu_add_script (scheme *sc, pointer a)
+script_fu_add_script (scheme  *sc,
+                      pointer  a)
 {
-  GimpParamDef *args;
-  SFScript     *script;
-  GType         enum_type;
-  GEnumValue   *enum_value;
-  gchar        *val;
-  gint          i;
-  guchar        r, g, b;
-  pointer       color_list;
-  pointer       adj_list;
-  pointer       brush_list;
-  pointer       option_list;
+  SFScript    *script;
+  const gchar *name;
+  const gchar *menu_label;
+  const gchar *blurb;
+  const gchar *author;
+  const gchar *copyright;
+  const gchar *date;
+  const gchar *image_types;
+  gint         n_args;
+  gint         i;
 
   /*  Check the length of a  */
   if (sc->vptr->list_length (sc, a) < 7)
-  {
-    g_message ("Too few arguments to script-fu-register");
-    return sc->NIL;
-  }
-
-  /*  Create a new script  */
-  script = g_slice_new0 (SFScript);
+    {
+      g_message (_("Too few arguments to 'script-fu-register' call"));
+      return sc->NIL;
+    }
 
   /*  Find the script name  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->name = g_strdup (val);
+  name = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
-  /*  Find the script menu_path  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->menu_path = g_strdup (val);
+  /*  Find the script menu_label  */
+  menu_label = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
   /*  Find the script blurb  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->blurb = g_strdup (val);
+  blurb = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
   /*  Find the script author  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->author = g_strdup (val);
+  author = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
   /*  Find the script copyright  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->copyright = g_strdup (val);
+  copyright = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
   /*  Find the script date  */
-  val = sc->vptr->string_value (sc->vptr->pair_car (a));
-  script->date = g_strdup (val);
+  date = sc->vptr->string_value (sc->vptr->pair_car (a));
   a = sc->vptr->pair_cdr (a);
 
   /*  Find the script image types  */
   if (sc->vptr->is_pair (a))
     {
-      val = sc->vptr->string_value (sc->vptr->pair_car (a));
+      image_types = sc->vptr->string_value (sc->vptr->pair_car (a));
       a = sc->vptr->pair_cdr (a);
     }
   else
     {
-      val = sc->vptr->string_value (a);
+      image_types = sc->vptr->string_value (a);
       a = sc->NIL;
     }
-  script->img_types = g_strdup (val);
 
   /*  Check the supplied number of arguments  */
-  script->num_args = sc->vptr->list_length (sc, a) / 3;
+  n_args = sc->vptr->list_length (sc, a) / 3;
 
-  args = g_new0 (GimpParamDef, script->num_args + 1);
+  /*  Create a new script  */
+  script = script_fu_script_new (name,
+                                 menu_label,
+                                 blurb,
+                                 author,
+                                 copyright,
+                                 date,
+                                 image_types,
+                                 n_args);
+
+  for (i = 0; i < script->n_args; i++)
+    {
+      SFArg *arg = &script->args[i];
 
-  args[0].type        = GIMP_PDB_INT32;
-  args[0].name        = "run-mode";
-  args[0].description = "Interactive, non-interactive";
+      if (a != sc->NIL)
+        {
+          if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
+            return foreign_error (sc, "script-fu-register: argument types must be integer values", 0);
 
-  script->arg_types    = g_new0 (SFArgType, script->num_args);
-  script->arg_labels   = g_new0 (gchar *, script->num_args);
-  script->arg_defaults = g_new0 (SFArgValue, script->num_args);
-  script->arg_values   = g_new0 (SFArgValue, script->num_args);
+          arg->type = sc->vptr->ivalue (sc->vptr->pair_car (a));
+          a = sc->vptr->pair_cdr (a);
+        }
+      else
+        return foreign_error (sc, "script-fu-register: missing type specifier", 0);
 
-  if (script->num_args > 0)
-    {
-      for (i = 0; i < script->num_args; i++)
+      if (a != sc->NIL)
         {
-          if (a != sc->NIL)
+          if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+            return foreign_error (sc, "script-fu-register: argument labels must be strings", 0);
+
+          arg->label = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+          a = sc->vptr->pair_cdr (a);
+        }
+      else
+        return foreign_error (sc, "script-fu-register: missing arguments label", 0);
+
+      if (a != sc->NIL)
+        {
+          switch (arg->type)
             {
+            case SF_IMAGE:
+            case SF_DRAWABLE:
+            case SF_LAYER:
+            case SF_CHANNEL:
+            case SF_VECTORS:
+            case SF_DISPLAY:
               if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
-                return foreign_error (sc, "script-fu-register: argument types must be integer values", 0);
-              script->arg_types[i] = sc->vptr->ivalue (sc->vptr->pair_car (a));
-              a = sc->vptr->pair_cdr (a);
-            }
-          else
-            return foreign_error (sc, "script-fu-register: missing type specifier", 0);
+                return foreign_error (sc, "script-fu-register: default IDs must be integer values", 0);
 
-          if (a != sc->NIL)
-            {
-              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                return foreign_error (sc, "script-fu-register: argument labels must be strings", 0);
-              script->arg_labels[i] = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-              a = sc->vptr->pair_cdr (a);
-            }
-          else
-            return foreign_error (sc, "script-fu-register: missing arguments label", 0);
+              arg->default_value.sfa_image =
+                sc->vptr->ivalue (sc->vptr->pair_car (a));
+              break;
 
-          if (a != sc->NIL)
-            {
-              switch (script->arg_types[i])
+            case SF_COLOR:
+              if (sc->vptr->is_string (sc->vptr->pair_car (a)))
                 {
-                case SF_IMAGE:
-                case SF_DRAWABLE:
-                case SF_LAYER:
-                case SF_CHANNEL:
-                case SF_VECTORS:
-                case SF_DISPLAY:
-                  if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: default IDs must be integer values", 0);
-                  script->arg_defaults[i].sfa_image =
-                      sc->vptr->ivalue (sc->vptr->pair_car (a));
-                  script->arg_values[i].sfa_image =
-                    script->arg_defaults[i].sfa_image;
-
-                  switch (script->arg_types[i])
-                    {
-                    case SF_IMAGE:
-                      args[i + 1].type = GIMP_PDB_IMAGE;
-                      args[i + 1].name = "image";
-                      break;
-
-                    case SF_DRAWABLE:
-                      args[i + 1].type = GIMP_PDB_DRAWABLE;
-                      args[i + 1].name = "drawable";
-                      break;
-
-                    case SF_LAYER:
-                      args[i + 1].type = GIMP_PDB_LAYER;
-                      args[i + 1].name = "layer";
-                      break;
-
-                    case SF_CHANNEL:
-                      args[i + 1].type = GIMP_PDB_CHANNEL;
-                      args[i + 1].name = "channel";
-                      break;
-
-                    case SF_VECTORS:
-                      args[i + 1].type = GIMP_PDB_VECTORS;
-                      args[i + 1].name = "vectors";
-                      break;
-
-                    case SF_DISPLAY:
-                      args[i + 1].type = GIMP_PDB_DISPLAY;
-                      args[i + 1].name = "display";
-                      break;
-
-                    default:
-                      break;
-                    }
-
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_COLOR:
-                  if (sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    {
-                      if (! gimp_rgb_parse_css (&script->arg_defaults[i].sfa_color,
-                                                sc->vptr->string_value (sc->vptr->pair_car (a)),
-                                                -1))
-                        return foreign_error (sc, "script-fu-register: invalid default color name", 0);
-                      gimp_rgb_set_alpha (&script->arg_defaults[i].sfa_color,
-                                          1.0);
-                    }
-                  else if (sc->vptr->is_list (sc, sc->vptr->pair_car (a)) &&
-                           sc->vptr->list_length(sc, sc->vptr->pair_car (a)) == 3)
-                    {
-                      color_list = sc->vptr->pair_car (a);
-                      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_rgb_set_uchar (&script->arg_defaults[i].sfa_color, r, g, b);
-                    }
-                  else
-                    {
-                      return foreign_error (sc, "script-fu-register: color defaults must be a list of 3 
integers or a color name", 0);
-                    }
-
-                  script->arg_values[i].sfa_color = script->arg_defaults[i].sfa_color;
-
-                  args[i + 1].type        = GIMP_PDB_COLOR;
-                  args[i + 1].name        = "color";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_TOGGLE:
-                  if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: toggle default must be an integer value", 
0);
-
-                  script->arg_defaults[i].sfa_toggle =
-                    (sc->vptr->ivalue (sc->vptr->pair_car (a))) ? TRUE : FALSE;
-                  script->arg_values[i].sfa_toggle =
-                    script->arg_defaults[i].sfa_toggle;
-
-                  args[i + 1].type        = GIMP_PDB_INT32;
-                  args[i + 1].name        = "toggle";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_VALUE:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: value defaults must be string values", 0);
-
-                  script->arg_defaults[i].sfa_value =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_value =
-                    g_strdup (script->arg_defaults[i].sfa_value);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "value";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_STRING:
-                case SF_TEXT:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: string defaults must be string values", 
0);
-
-                  script->arg_defaults[i].sfa_value =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_value =
-                    g_strdup (script->arg_defaults[i].sfa_value);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "string";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_ADJUSTMENT:
-                  if (!sc->vptr->is_list (sc, a))
-                    return foreign_error (sc, "script-fu-register: adjustment defaults must be a list", 0);
-
-                  adj_list = sc->vptr->pair_car (a);
-                  script->arg_defaults[i].sfa_adjustment.value =
-                    sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.lower =
-                    sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.upper =
-                    sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.step =
-                    sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.page =
-                    sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.digits =
-                    sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
-
-                  adj_list = sc->vptr->pair_cdr (adj_list);
-                  script->arg_defaults[i].sfa_adjustment.type =
-                    sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
-
-                  script->arg_values[i].sfa_adjustment.adj = NULL;
-                  script->arg_values[i].sfa_adjustment.value =
-                    script->arg_defaults[i].sfa_adjustment.value;
-
-                  args[i + 1].type        = GIMP_PDB_FLOAT;
-                  args[i + 1].name        = "value";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_FILENAME:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: filename defaults must be string values", 
0);
-                  /* fallthrough */
-
-                case SF_DIRNAME:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: dirname defaults must be string values", 
0);
-
-                  script->arg_defaults[i].sfa_file.filename =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+                  if (! gimp_rgb_parse_css (&arg->default_value.sfa_color,
+                                            sc->vptr->string_value (sc->vptr->pair_car (a)),
+                                            -1))
+                    return foreign_error (sc, "script-fu-register: invalid default color name", 0);
+
+                  gimp_rgb_set_alpha (&arg->default_value.sfa_color, 1.0);
+                }
+              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, g, b;
+
+                  color_list = sc->vptr->pair_car (a);
+                  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_rgb_set_uchar (&arg->default_value.sfa_color, r, g, b);
+                }
+              else
+                {
+                  return foreign_error (sc, "script-fu-register: color defaults must be a list of 3 integers 
or a color name", 0);
+                }
+              break;
+
+            case SF_TOGGLE:
+              if (!sc->vptr->is_integer (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: toggle default must be an integer value", 0);
+
+              arg->default_value.sfa_toggle =
+                (sc->vptr->ivalue (sc->vptr->pair_car (a))) ? TRUE : FALSE;
+              break;
+
+            case SF_VALUE:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: value defaults must be string values", 0);
+
+              arg->default_value.sfa_value =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_STRING:
+            case SF_TEXT:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: string defaults must be string values", 0);
+
+              arg->default_value.sfa_value =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_ADJUSTMENT:
+              {
+                pointer adj_list;
+
+                if (!sc->vptr->is_list (sc, a))
+                  return foreign_error (sc, "script-fu-register: adjustment defaults must be a list", 0);
+
+                adj_list = sc->vptr->pair_car (a);
+                arg->default_value.sfa_adjustment.value =
+                  sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.lower =
+                  sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.upper =
+                  sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.step =
+                  sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.page =
+                  sc->vptr->rvalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.digits =
+                  sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
+
+                adj_list = sc->vptr->pair_cdr (adj_list);
+                arg->default_value.sfa_adjustment.type =
+                  sc->vptr->ivalue (sc->vptr->pair_car (adj_list));
+              }
+              break;
+
+            case SF_FILENAME:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: filename defaults must be string values", 0);
+              /* fallthrough */
+
+            case SF_DIRNAME:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: dirname defaults must be string values", 0);
+
+              arg->default_value.sfa_file.filename =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
 
 #ifdef G_OS_WIN32
-                  /* Replace POSIX slashes with Win32 backslashes. This
-                   * is just so script-fus can be written with only
-                   * POSIX directory separators.
-                   */
-                  val = script->arg_defaults[i].sfa_file.filename;
-                  while (*val)
-                    {
-                      if (*val == '/')
-                        *val = G_DIR_SEPARATOR;
-                      val++;
-                    }
+              {
+                /* Replace POSIX slashes with Win32 backslashes. This
+                 * is just so script-fus can be written with only
+                 * POSIX directory separators.
+                 */
+                gchar *filename = arg->default_value.sfa_file.filename;
+
+                while (*filename)
+                  {
+                    if (*filename == '/')
+                      *filename = G_DIR_SEPARATOR;
+
+                    filename++;
+                  }
+              }
 #endif
-                  script->arg_values[i].sfa_file.filename =
-                    g_strdup (script->arg_defaults[i].sfa_file.filename);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = (script->arg_types[i] == SF_FILENAME ?
-                                             "filename" : "dirname");
-                  args[i + 1].description = script->arg_labels[i];
-                 break;
-
-                case SF_FONT:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: font defaults must be string values", 0);
-
-                  script->arg_defaults[i].sfa_font =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_font =
-                    g_strdup (script->arg_defaults[i].sfa_font);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "font";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_PALETTE:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: palette defaults must be string values", 
0);
-
-                  script->arg_defaults[i].sfa_palette =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_palette =
-                    g_strdup (script->arg_defaults[i].sfa_pattern);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "palette";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_PATTERN:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: pattern defaults must be string values", 
0);
-
-                  script->arg_defaults[i].sfa_pattern =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_pattern =
-                    g_strdup (script->arg_defaults[i].sfa_pattern);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "pattern";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_BRUSH:
-                  if (!sc->vptr->is_list (sc, a))
-                    return foreign_error (sc, "script-fu-register: brush defaults must be a list", 0);
-
-                  brush_list = sc->vptr->pair_car (a);
-                  script->arg_defaults[i].sfa_brush.name =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (brush_list)));
-                  script->arg_values[i].sfa_brush.name =
-                    g_strdup (script->arg_defaults[i].sfa_brush.name);
-
-                  brush_list = sc->vptr->pair_cdr (brush_list);
-                  script->arg_defaults[i].sfa_brush.opacity =
-                    sc->vptr->rvalue (sc->vptr->pair_car (brush_list));
-                  script->arg_values[i].sfa_brush.opacity =
-                    script->arg_defaults[i].sfa_brush.opacity;
-
-                  brush_list = sc->vptr->pair_cdr (brush_list);
-                  script->arg_defaults[i].sfa_brush.spacing =
-                    sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
-                  script->arg_values[i].sfa_brush.spacing =
-                    script->arg_defaults[i].sfa_brush.spacing;
-
-                  brush_list = sc->vptr->pair_cdr (brush_list);
-                  script->arg_defaults[i].sfa_brush.paint_mode =
-                    sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
-                  script->arg_values[i].sfa_brush.paint_mode =
-                    script->arg_defaults[i].sfa_brush.paint_mode;
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "brush";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_GRADIENT:
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
-                    return foreign_error (sc, "script-fu-register: gradient defaults must be string values", 
0);
-
-                  script->arg_defaults[i].sfa_gradient =
-                    g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
-                  script->arg_values[i].sfa_gradient =
-                    g_strdup (script->arg_defaults[i].sfa_gradient);
-
-                  args[i + 1].type        = GIMP_PDB_STRING;
-                  args[i + 1].name        = "gradient";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_OPTION:
-                  if (!sc->vptr->is_list (sc, a))
-                    return foreign_error (sc, "script-fu-register: option defaults must be a list", 0);
-
-                  for (option_list = sc->vptr->pair_car (a);
-                       option_list != sc->NIL;
-                       option_list = sc->vptr->pair_cdr (option_list))
-                    {
-                      script->arg_defaults[i].sfa_option.list =
-                        g_slist_append (script->arg_defaults[i].sfa_option.list,
-                                        g_strdup (sc->vptr->string_value
-                                           (sc->vptr->pair_car (option_list))));
-                    }
-
-                  script->arg_defaults[i].sfa_option.history = 0;
-                  script->arg_values[i].sfa_option.history = 0;
-
-                  args[i + 1].type        = GIMP_PDB_INT32;
-                  args[i + 1].name        = "option";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-
-                case SF_ENUM:
-                  if (!sc->vptr->is_list (sc, a))
-                    return foreign_error (sc, "script-fu-register: enum defaults must be a list", 0);
-
-                  option_list = sc->vptr->pair_car (a);
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
-                    return foreign_error (sc, "script-fu-register: first element in enum defaults must be a 
type-name", 0);
-
-                  val =
-                    sc->vptr->string_value (sc->vptr->pair_car (option_list));
-                  if (g_str_has_prefix (val, "Gimp"))
-                    val = g_strdup (val);
-                  else
-                    val = g_strconcat ("Gimp", val, NULL);
-
-                  enum_type = g_type_from_name (val);
-                  if (! G_TYPE_IS_ENUM (enum_type))
-                    {
-                      g_free (val);
-                      return foreign_error (sc, "script-fu-register: first element in enum defaults must be 
the name of a registered type", 0);
-                    }
-
-                  script->arg_defaults[i].sfa_enum.type_name = val;
-
-                  option_list = sc->vptr->pair_cdr (option_list);
-                  if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
-                    return foreign_error (sc, "script-fu-register: second element in enum defaults must be a 
string", 0);
-
-                  enum_value =
-                    g_enum_get_value_by_nick (g_type_class_peek (enum_type),
-                      sc->vptr->string_value (sc->vptr->pair_car (option_list)));
-                  if (enum_value)
-                    script->arg_defaults[i].sfa_enum.history =
-                      script->arg_values[i].sfa_enum.history = enum_value->value;
-
-                  args[i + 1].type        = GIMP_PDB_INT32;
-                  args[i + 1].name        = "enum";
-                  args[i + 1].description = script->arg_labels[i];
-                  break;
-                }
+              break;
 
-              a = sc->vptr->pair_cdr (a);
-            }
-          else
-            {
-              return foreign_error (sc, "script-fu-register: missing default argument", 0);
+            case SF_FONT:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: font defaults must be string values", 0);
+
+              arg->default_value.sfa_font =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_PALETTE:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: palette defaults must be string values", 0);
+
+              arg->default_value.sfa_palette =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_PATTERN:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: pattern defaults must be string values", 0);
+
+              arg->default_value.sfa_pattern =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_BRUSH:
+              {
+                pointer brush_list;
+
+                if (!sc->vptr->is_list (sc, a))
+                  return foreign_error (sc, "script-fu-register: brush defaults must be a list", 0);
+
+                brush_list = sc->vptr->pair_car (a);
+                arg->default_value.sfa_brush.name =
+                  g_strdup (sc->vptr->string_value (sc->vptr->pair_car (brush_list)));
+
+                brush_list = sc->vptr->pair_cdr (brush_list);
+                arg->default_value.sfa_brush.opacity =
+                  sc->vptr->rvalue (sc->vptr->pair_car (brush_list));
+
+                brush_list = sc->vptr->pair_cdr (brush_list);
+                arg->default_value.sfa_brush.spacing =
+                  sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
+
+                brush_list = sc->vptr->pair_cdr (brush_list);
+                arg->default_value.sfa_brush.paint_mode =
+                  sc->vptr->ivalue (sc->vptr->pair_car (brush_list));
+              }
+              break;
+
+            case SF_GRADIENT:
+              if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+                return foreign_error (sc, "script-fu-register: gradient defaults must be string values", 0);
+
+              arg->default_value.sfa_gradient =
+                g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+              break;
+
+            case SF_OPTION:
+              {
+                pointer option_list;
+
+                if (!sc->vptr->is_list (sc, a))
+                  return foreign_error (sc, "script-fu-register: option defaults must be a list", 0);
+
+                for (option_list = sc->vptr->pair_car (a);
+                     option_list != sc->NIL;
+                     option_list = sc->vptr->pair_cdr (option_list))
+                  {
+                    arg->default_value.sfa_option.list =
+                      g_slist_append (arg->default_value.sfa_option.list,
+                                      g_strdup (sc->vptr->string_value
+                                                (sc->vptr->pair_car (option_list))));
+                  }
+              }
+              break;
+
+            case SF_ENUM:
+              {
+                pointer      option_list;
+                const gchar *val;
+                gchar       *type_name;
+                GEnumValue  *enum_value;
+                GType        enum_type;
+
+                if (!sc->vptr->is_list (sc, a))
+                  return foreign_error (sc, "script-fu-register: enum defaults must be a list", 0);
+
+                option_list = sc->vptr->pair_car (a);
+                if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
+                  return foreign_error (sc, "script-fu-register: first element in enum defaults must be a 
type-name", 0);
+
+                val = sc->vptr->string_value (sc->vptr->pair_car (option_list));
+
+                if (g_str_has_prefix (val, "Gimp"))
+                  type_name = g_strdup (val);
+                else
+                  type_name = g_strconcat ("Gimp", val, NULL);
+
+                enum_type = g_type_from_name (type_name);
+                if (! G_TYPE_IS_ENUM (enum_type))
+                  {
+                    g_free (type_name);
+                    return foreign_error (sc, "script-fu-register: first element in enum defaults must be 
the name of a registered type", 0);
+                  }
+
+                arg->default_value.sfa_enum.type_name = type_name;
+
+                option_list = sc->vptr->pair_cdr (option_list);
+                if (!sc->vptr->is_string (sc->vptr->pair_car (option_list)))
+                  return foreign_error (sc, "script-fu-register: second element in enum defaults must be a 
string", 0);
+
+                enum_value =
+                  g_enum_get_value_by_nick (g_type_class_peek (enum_type),
+                                            sc->vptr->string_value (sc->vptr->pair_car (option_list)));
+                if (enum_value)
+                  arg->default_value.sfa_enum.history = enum_value->value;
+              }
+              break;
             }
+
+          a = sc->vptr->pair_cdr (a);
+        }
+      else
+        {
+          return foreign_error (sc, "script-fu-register: missing default argument", 0);
         }
     }
 
-  script->args = args;
+  /*  fill all values from defaults  */
+  script_fu_script_reset (script, TRUE);
 
-  script_fu_menu_map (script);
+  if (script->menu_label[0] == '<')
+    {
+      gchar *mapped = script_fu_menu_map (script->menu_label);
+
+      if (mapped)
+        {
+          g_free (script->menu_label);
+          script->menu_label = mapped;
+        }
+    }
 
   {
-    const gchar *key  = gettext (script->menu_path);
+    const gchar *key  = gettext (script->menu_label);
     GList       *list = g_tree_lookup (script_tree, key);
 
     g_tree_insert (script_tree, (gpointer) key, g_list_append (list, script));
@@ -616,11 +516,13 @@ script_fu_add_script (scheme *sc, pointer a)
 }
 
 pointer
-script_fu_add_menu (scheme *sc, pointer a)
+script_fu_add_menu (scheme  *sc,
+                    pointer  a)
 {
   SFScript    *script;
   SFMenu      *menu;
   const gchar *name;
+  const gchar *path;
 
   /*  Check the length of a  */
   if (sc->vptr->list_length (sc, a) != 2)
@@ -633,10 +535,11 @@ script_fu_add_menu (scheme *sc, pointer a)
   script = script_fu_find_script (name);
 
   if (! script)
-  {
-    g_message ("Procedure %s in script-fu-menu-register does not exist", name);
-    return sc->NIL;
-  }
+    {
+      g_message ("Procedure %s in script-fu-menu-register does not exist",
+                 name);
+      return sc->NIL;
+    }
 
   /*  Create a new list of menus  */
   menu = g_slice_new0 (SFMenu);
@@ -644,23 +547,44 @@ script_fu_add_menu (scheme *sc, pointer a)
   menu->script = script;
 
   /*  Find the script menu path  */
-  menu->menu_path = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+  path = sc->vptr->string_value (sc->vptr->pair_car (a));
+
+  menu->menu_path = script_fu_menu_map (path);
+
+  if (! menu->menu_path)
+    menu->menu_path = g_strdup (path);
 
   script_menu_list = g_list_prepend (script_menu_list, menu);
 
   return sc->NIL;
 }
 
-void
-script_fu_error_msg (const gchar *command,
-                     const gchar *msg)
+
+/*  private functions  */
+
+static gboolean
+script_fu_run_command (const gchar  *command,
+                       GError      **error)
 {
-  g_message (_("Error while executing\n%s\n\n%s"),
-             command, msg);
-}
+  GString  *output;
+  gboolean  success = FALSE;
 
+  output = g_string_new (NULL);
+  ts_register_output_func (ts_gstring_output_func, output);
 
-/*  private functions  */
+  if (ts_interpret_string (command))
+    {
+      g_set_error (error, 0, 0, "%s", output->str);
+    }
+  else
+    {
+      success = TRUE;
+    }
+
+  g_string_free (output, TRUE);
+
+  return success;
+}
 
 static void
 script_fu_load_script (const GimpDatafileData *file_data,
@@ -668,18 +592,25 @@ script_fu_load_script (const GimpDatafileData *file_data,
 {
   if (gimp_datafiles_check_extension (file_data->filename, ".scm"))
     {
-      gchar   *command;
-      gchar   *escaped = script_fu_strescape (file_data->filename);
-      GString *output;
+      gchar  *escaped = script_fu_strescape (file_data->filename);
+      gchar  *command;
+      GError *error   = NULL;
 
       command = g_strdup_printf ("(load \"%s\")", escaped);
       g_free (escaped);
 
-      output = g_string_new ("");
-      ts_register_output_func (ts_gstring_output_func, output);
-      if (ts_interpret_string (command))
-        script_fu_error_msg (command, output->str);
-      g_string_free (output, TRUE);
+      if (! script_fu_run_command (command, &error))
+        {
+          gchar *display_name = g_filename_display_name (file_data->filename);
+          gchar *message      = g_strdup_printf (_("Error while loading %s:"),
+                                                 display_name);
+
+          g_message ("%s\n\n%s", message, error->message);
+
+          g_clear_error (&error);
+          g_free (message);
+          g_free (display_name);
+        }
 
 #ifdef G_OS_WIN32
       /* No, I don't know why, but this is
@@ -694,7 +625,6 @@ script_fu_load_script (const GimpDatafileData *file_data,
 
 /*
  *  The following function is a GTraverseFunction.
- *  Please note that it frees the script->args structure.
  */
 static gboolean
 script_fu_install_script (gpointer  foo G_GNUC_UNUSED,
@@ -705,28 +635,9 @@ script_fu_install_script (gpointer  foo G_GNUC_UNUSED,
 
   for (list = scripts; list; list = g_list_next (list))
     {
-      SFScript    *script    = list->data;
-      const gchar *menu_path = NULL;
-
-      /* Allow scripts with no menus */
-      if (strncmp (script->menu_path, "<None>", 6) != 0)
-        menu_path = script->menu_path;
-
-      gimp_install_temp_proc (script->name,
-                              script->blurb,
-                              "",
-                              script->author,
-                              script->copyright,
-                              script->date,
-                              menu_path,
-                              script->img_types,
-                              GIMP_TEMPORARY,
-                              script->num_args + 1, 0,
-                              script->args, NULL,
-                              script_fu_script_proc);
-
-      g_free (script->args);
-      script->args = NULL;
+      SFScript *script = list->data;
+
+      script_fu_script_install_proc (script, script_fu_script_proc);
     }
 
   return FALSE;
@@ -752,121 +663,16 @@ script_fu_remove_script (gpointer  foo G_GNUC_UNUSED,
   GList *list;
 
   for (list = scripts; list; list = g_list_next (list))
-    script_fu_free_script (list->data);
-
-  g_list_free (scripts);
-
-  return FALSE;
-}
-
-static gboolean
-script_fu_param_init (SFScript        *script,
-                      gint             nparams,
-                      const GimpParam *params,
-                      SFArgType        type,
-                      gint             n)
-{
-  if (script->num_args > n && script->arg_types[n] == type && nparams > n + 1)
     {
-      switch (type)
-        {
-        case SF_IMAGE:
-          if (params[n + 1].type == GIMP_PDB_IMAGE)
-            {
-              script->arg_values[n].sfa_image = params[n + 1].data.d_image;
-              return TRUE;
-            }
-          break;
-
-        case SF_DRAWABLE:
-          if (params[n + 1].type == GIMP_PDB_DRAWABLE)
-            {
-              script->arg_values[n].sfa_drawable = params[n + 1].data.d_drawable;
-              return TRUE;
-            }
-          break;
-
-        case SF_LAYER:
-          if (params[n + 1].type == GIMP_PDB_LAYER)
-            {
-              script->arg_values[n].sfa_layer = params[n + 1].data.d_layer;
-              return TRUE;
-            }
-          break;
-
-        case SF_CHANNEL:
-          if (params[n + 1].type == GIMP_PDB_CHANNEL)
-            {
-              script->arg_values[n].sfa_channel = params[n + 1].data.d_channel;
-              return TRUE;
-            }
-          break;
-
-        case SF_VECTORS:
-          if (params[n + 1].type == GIMP_PDB_VECTORS)
-            {
-              script->arg_values[n].sfa_vectors = params[n + 1].data.d_vectors;
-              return TRUE;
-            }
-          break;
-
-        case SF_DISPLAY:
-          if (params[n + 1].type == GIMP_PDB_DISPLAY)
-            {
-              script->arg_values[n].sfa_display = params[n + 1].data.d_display;
-              return TRUE;
-            }
-          break;
-
-        default:
-          break;
-        }
-    }
-
-  return FALSE;
-}
-
-static gint
-script_fu_collect_standard_args (SFScript        *script,
-                                 gint             nparams,
-                                 const GimpParam *params)
-{
-  gint params_consumed = 0;
+      SFScript *script = list->data;
 
-  /*  the first parameter may be a DISPLAY id  */
-  if (script_fu_param_init (script,
-                            nparams, params, SF_DISPLAY, params_consumed))
-    {
-      params_consumed++;
+      script_fu_script_uninstall_proc (script);
+      script_fu_script_free (script);
     }
 
-  /*  an IMAGE id may come first or after the DISPLAY id  */
-  if (script_fu_param_init (script,
-                            nparams, params, SF_IMAGE, params_consumed))
-    {
-      params_consumed++;
-
-      /*  and may be followed by a DRAWABLE, LAYER, CHANNEL or
-       *  VECTORS id
-       */
-      if (script_fu_param_init (script,
-                                nparams, params, SF_DRAWABLE,
-                                params_consumed) ||
-          script_fu_param_init (script,
-                                nparams, params, SF_LAYER,
-                                params_consumed) ||
-          script_fu_param_init (script,
-                                nparams, params, SF_CHANNEL,
-                                params_consumed) ||
-          script_fu_param_init (script,
-                                nparams, params, SF_VECTORS,
-                                params_consumed))
-        {
-          params_consumed++;
-        }
-    }
+  g_list_free (scripts);
 
-  return params_consumed;
+  return FALSE;
 }
 
 static void
@@ -876,9 +682,21 @@ script_fu_script_proc (const gchar      *name,
                        gint             *nreturn_vals,
                        GimpParam       **return_vals)
 {
-  static GimpParam   values[1];
-  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+  static GimpParam   values[2] = { { 0, }, { 0, } };
+  GimpPDBStatusType  status    = GIMP_PDB_SUCCESS;
   SFScript          *script;
+  GError            *error     = NULL;
+
+  if (values[1].type == GIMP_PDB_STRING && values[1].data.d_string)
+    {
+      g_free (values[1].data.d_string);
+      values[1].data.d_string = NULL;
+    }
+
+  *nreturn_vals = 1;
+  *return_vals  = values;
+
+  values[0].type = GIMP_PDB_STATUS;
 
   script = script_fu_find_script (name);
 
@@ -889,7 +707,7 @@ script_fu_script_proc (const gchar      *name,
     {
       GimpRunMode run_mode = params[0].data.d_int32;
 
-      set_run_mode_constant (run_mode);
+      ts_set_run_mode (run_mode);
 
       switch (run_mode)
         {
@@ -898,13 +716,13 @@ script_fu_script_proc (const gchar      *name,
             gint min_args = 0;
 
             /*  First, try to collect the standard script arguments...  */
-            min_args = script_fu_collect_standard_args (script,
-                                                        nparams, params);
+            min_args = script_fu_script_collect_standard_args (script,
+                                                               nparams, params);
 
             /*  ...then acquire the rest of arguments (if any) with a dialog  */
-            if (script->num_args > min_args)
+            if (script->n_args > min_args)
               {
-                script_fu_interface (script, min_args);
+                status = script_fu_interface (script, min_args);
                 break;
               }
             /*  otherwise (if the script takes no more arguments), skip
@@ -914,104 +732,27 @@ script_fu_script_proc (const gchar      *name,
 
         case GIMP_RUN_NONINTERACTIVE:
           /*  Make sure all the arguments are there  */
-          if (nparams != (script->num_args + 1))
+          if (nparams != (script->n_args + 1))
             status = GIMP_PDB_CALLING_ERROR;
 
           if (status == GIMP_PDB_SUCCESS)
             {
-              GString *s;
-              GString *output;
-              gchar   *command;
-              gint     i;
+              gchar *command;
 
-              s = g_string_new ("(");
-              g_string_append (s, script->name);
+              command = script_fu_script_get_command_from_params (script,
+                                                                  params);
 
-              for (i = 0; i < script->num_args; i++)
+              /*  run the command through the interpreter  */
+              if (! script_fu_run_command (command, &error))
                 {
-                  const GimpParam *param = &params[i + 1];
-
-                  g_string_append_c (s, ' ');
-
-                  switch (script->arg_types[i])
-                    {
-                    case SF_IMAGE:
-                    case SF_DRAWABLE:
-                    case SF_LAYER:
-                    case SF_CHANNEL:
-                    case SF_VECTORS:
-                    case SF_DISPLAY:
-                      g_string_append_printf (s, "%d", param->data.d_int32);
-                      break;
-
-                    case SF_COLOR:
-                      {
-                        guchar r, g, b;
-
-                        gimp_rgb_get_uchar (&param->data.d_color, &r, &g, &b);
-                        g_string_append_printf (s, "'(%d %d %d)",
-                                                (gint) r, (gint) g, (gint) b);
-                      }
-                      break;
-
-                    case SF_TOGGLE:
-                      g_string_append_printf (s, (param->data.d_int32 ?
-                                                  "TRUE" : "FALSE"));
-                      break;
-
-                    case SF_VALUE:
-                      g_string_append (s, param->data.d_string);
-                      break;
-
-                    case SF_STRING:
-                    case SF_TEXT:
-                    case SF_FILENAME:
-                    case SF_DIRNAME:
-                      {
-                        gchar *tmp;
-
-                        tmp = script_fu_strescape (param->data.d_string);
-                        g_string_append_printf (s, "\"%s\"", tmp);
-                        g_free (tmp);
-                      }
-                      break;
-
-                    case SF_ADJUSTMENT:
-                      {
-                        gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
-
-                        g_ascii_dtostr (buffer, sizeof (buffer),
-                                        param->data.d_float);
-                        g_string_append (s, buffer);
-                      }
-                      break;
-
-                    case SF_FONT:
-                    case SF_PALETTE:
-                    case SF_PATTERN:
-                    case SF_GRADIENT:
-                    case SF_BRUSH:
-                      g_string_append_printf (s, "\"%s\"",
-                                              param->data.d_string);
-                      break;
-
-                    case SF_OPTION:
-                    case SF_ENUM:
-                      g_string_append_printf (s, "%d", param->data.d_int32);
-                      break;
-                    }
-                }
-
-              g_string_append_c (s, ')');
+                  status                  = GIMP_PDB_EXECUTION_ERROR;
+                  *nreturn_vals           = 2;
+                  values[1].type          = GIMP_PDB_STRING;
+                  values[1].data.d_string = error->message;
 
-              command = g_string_free (s, FALSE);
-
-              /*  run the command through the interpreter  */
-              output = g_string_new ("");
-              ts_register_output_func (ts_gstring_output_func, output);
-              if (ts_interpret_string (command))
-                script_fu_error_msg (command, output->str);
-              g_string_free (output, TRUE);
+                  error->message = NULL;
+                  g_error_free (error);
+                }
 
               g_free (command);
             }
@@ -1019,135 +760,25 @@ script_fu_script_proc (const gchar      *name,
 
         case GIMP_RUN_WITH_LAST_VALS:
           {
-            GString *s;
-            GString *output;
-            gchar   *command;
-            gint     i;
+            gchar *command;
 
             /*  First, try to collect the standard script arguments  */
-            script_fu_collect_standard_args (script, nparams, params);
+            script_fu_script_collect_standard_args (script, nparams, params);
 
-            s = g_string_new ("(");
-            g_string_append (s, script->name);
+            command = script_fu_script_get_command (script);
 
-            for (i = 0; i < script->num_args; i++)
+            /*  run the command through the interpreter  */
+            if (! script_fu_run_command (command, &error))
               {
-                SFArgValue *arg_value = &script->arg_values[i];
+                status                  = GIMP_PDB_EXECUTION_ERROR;
+                *nreturn_vals           = 2;
+                values[1].type          = GIMP_PDB_STRING;
+                values[1].data.d_string = error->message;
 
-                g_string_append_c (s, ' ');
-
-                switch (script->arg_types[i])
-                  {
-                  case SF_IMAGE:
-                  case SF_DRAWABLE:
-                  case SF_LAYER:
-                  case SF_CHANNEL:
-                  case SF_VECTORS:
-                  case SF_DISPLAY:
-                    g_string_append_printf (s, "%d", arg_value->sfa_image);
-                    break;
-
-                  case SF_COLOR:
-                    {
-                      guchar r, g, b;
-
-                      gimp_rgb_get_uchar (&arg_value->sfa_color, &r, &g, &b);
-                      g_string_append_printf (s, "'(%d %d %d)",
-                                              (gint) r, (gint) g, (gint) b);
-                    }
-                    break;
-
-                  case SF_TOGGLE:
-                    g_string_append (s, arg_value->sfa_toggle ? "TRUE" : "FALSE");
-                    break;
-
-                  case SF_VALUE:
-                    g_string_append (s, arg_value->sfa_value);
-                    break;
-
-                  case SF_STRING:
-                  case SF_TEXT:
-                    {
-                      gchar *tmp;
-
-                      tmp = script_fu_strescape (arg_value->sfa_value);
-                      g_string_append_printf (s, "\"%s\"", tmp);
-                      g_free (tmp);
-                    }
-                    break;
-
-                  case SF_ADJUSTMENT:
-                    {
-                      gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
-
-                      g_ascii_dtostr (buffer, sizeof (buffer),
-                                      arg_value->sfa_adjustment.value);
-                      g_string_append (s, buffer);
-                    }
-                    break;
-
-                  case SF_FILENAME:
-                  case SF_DIRNAME:
-                    {
-                      gchar *tmp;
-
-                      tmp = script_fu_strescape (arg_value->sfa_file.filename);
-                      g_string_append_printf (s, "\"%s\"", tmp);
-                      g_free (tmp);
-                    }
-                    break;
-
-                  case SF_FONT:
-                    g_string_append_printf (s, "\"%s\"", arg_value->sfa_font);
-                    break;
-
-                  case SF_PALETTE:
-                    g_string_append_printf (s, "\"%s\"", arg_value->sfa_palette);
-                    break;
-
-                  case SF_PATTERN:
-                    g_string_append_printf (s, "\"%s\"", arg_value->sfa_pattern);
-                    break;
-
-                  case SF_GRADIENT:
-                    g_string_append_printf (s, "\"%s\"", arg_value->sfa_gradient);
-                    break;
-
-                  case SF_BRUSH:
-                    {
-                      gchar buffer[G_ASCII_DTOSTR_BUF_SIZE];
-
-                      g_ascii_dtostr (buffer, sizeof (buffer),
-                                      arg_value->sfa_brush.opacity);
-                      g_string_append_printf (s, "'(\"%s\" %s %d %d)",
-                                              arg_value->sfa_brush.name,
-                                              buffer,
-                                              arg_value->sfa_brush.spacing,
-                                              arg_value->sfa_brush.paint_mode);
-                    }
-                    break;
-
-                  case SF_OPTION:
-                    g_string_append_printf (s, "%d", arg_value->sfa_option.history);
-                    break;
-
-                  case SF_ENUM:
-                    g_string_append_printf (s, "%d", arg_value->sfa_enum.history);
-                    break;
-                  }
+                error->message = NULL;
+                g_error_free (error);
               }
 
-            g_string_append_c (s, ')');
-
-            command = g_string_free (s, FALSE);
-
-            /*  run the command through the interpreter  */
-            output = g_string_new ("");
-            ts_register_output_func (ts_gstring_output_func, output);
-            if (ts_interpret_string (command))
-              script_fu_error_msg (command, output->str);
-            g_string_free (output, TRUE);
-
             g_free (command);
           }
           break;
@@ -1157,10 +788,6 @@ script_fu_script_proc (const gchar      *name,
         }
     }
 
-  *nreturn_vals = 1;
-  *return_vals  = values;
-
-  values[0].type          = GIMP_PDB_STATUS;
   values[0].data.d_status = status;
 }
 
@@ -1202,102 +829,8 @@ script_fu_find_script (const gchar *name)
   return (SFScript *) script;
 }
 
-static void
-script_fu_free_script (SFScript *script)
-{
-  gint i;
-
-  g_return_if_fail (script != NULL);
-
-  /*  Uninstall the temporary procedure for this script  */
-  gimp_uninstall_temp_proc (script->name);
-
-  g_free (script->name);
-  g_free (script->blurb);
-  g_free (script->menu_path);
-  g_free (script->author);
-  g_free (script->copyright);
-  g_free (script->date);
-  g_free (script->img_types);
-
-  for (i = 0; i < script->num_args; i++)
-    {
-      g_free (script->arg_labels[i]);
-      switch (script->arg_types[i])
-        {
-        case SF_IMAGE:
-        case SF_DRAWABLE:
-        case SF_LAYER:
-        case SF_CHANNEL:
-        case SF_VECTORS:
-        case SF_DISPLAY:
-        case SF_COLOR:
-        case SF_TOGGLE:
-          break;
-
-        case SF_VALUE:
-        case SF_STRING:
-        case SF_TEXT:
-          g_free (script->arg_defaults[i].sfa_value);
-          g_free (script->arg_values[i].sfa_value);
-          break;
-
-        case SF_ADJUSTMENT:
-          break;
-
-        case SF_FILENAME:
-        case SF_DIRNAME:
-          g_free (script->arg_defaults[i].sfa_file.filename);
-          g_free (script->arg_values[i].sfa_file.filename);
-          break;
-
-        case SF_FONT:
-          g_free (script->arg_defaults[i].sfa_font);
-          g_free (script->arg_values[i].sfa_font);
-          break;
-
-        case SF_PALETTE:
-          g_free (script->arg_defaults[i].sfa_palette);
-          g_free (script->arg_values[i].sfa_palette);
-          break;
-
-        case SF_PATTERN:
-          g_free (script->arg_defaults[i].sfa_pattern);
-          g_free (script->arg_values[i].sfa_pattern);
-          break;
-
-        case SF_GRADIENT:
-          g_free (script->arg_defaults[i].sfa_gradient);
-          g_free (script->arg_values[i].sfa_gradient);
-          break;
-
-        case SF_BRUSH:
-          g_free (script->arg_defaults[i].sfa_brush.name);
-          g_free (script->arg_values[i].sfa_brush.name);
-          break;
-
-        case SF_OPTION:
-          g_slist_foreach (script->arg_defaults[i].sfa_option.list,
-                           (GFunc) g_free, NULL);
-          g_slist_free (script->arg_defaults[i].sfa_option.list);
-          break;
-
-        case SF_ENUM:
-          g_free (script->arg_defaults[i].sfa_enum.type_name);
-          break;
-        }
-    }
-
-  g_free (script->arg_labels);
-  g_free (script->arg_defaults);
-  g_free (script->arg_types);
-  g_free (script->arg_values);
-
-  g_slice_free (SFScript, script);
-}
-
-static void
-script_fu_menu_map (SFScript *script)
+static gchar *
+script_fu_menu_map (const gchar *menu_path)
 {
   /*  for backward compatibility, we fiddle with some menu paths  */
   const struct
@@ -1305,36 +838,32 @@ script_fu_menu_map (SFScript *script)
     const gchar *old;
     const gchar *new;
   } mapping[] = {
-    { "<Image>/Script-Fu/Alchemy",       "<Image>/Filters/Artistic"            },
-    { "<Image>/Script-Fu/Alpha to Logo", "<Image>/Filters/Alpha to Logo"       },
-    { "<Image>/Script-Fu/Animators",     "<Image>/Filters/Animation/Animators" },
-    { "<Image>/Script-Fu/Decor",         "<Image>/Filters/Decor"               },
-    { "<Image>/Script-Fu/Render",        "<Image>/Filters/Render"              },
-    { "<Image>/Script-Fu/Selection",     "<Image>/Select/Modify"               },
-    { "<Image>/Script-Fu/Shadow",        "<Image>/Filters/Light and Shadow/Shadow" },
-    { "<Image>/Script-Fu/Stencil Ops",   "<Image>/Filters/Decor"               }
+    { "<Image>/Tiny-Fu/Alchemy",       "<Image>/Filters/Artistic"            },
+    { "<Image>/Tiny-Fu/Alpha to Logo", "<Image>/Filters/Alpha to Logo"       },
+    { "<Image>/Tiny-Fu/Animators",     "<Image>/Filters/Animation/Animators" },
+    { "<Image>/Tiny-Fu/Decor",         "<Image>/Filters/Decor"               },
+    { "<Image>/Tiny-Fu/Render",        "<Image>/Filters/Render"              },
+    { "<Image>/Tiny-Fu/Selection",     "<Image>/Select/Modify"               },
+    { "<Image>/Tiny-Fu/Shadow",        "<Image>/Filters/Light and Shadow/Shadow" },
+    { "<Image>/Tiny-Fu/Stencil Ops",   "<Image>/Filters/Decor"               }
   };
 
   gint i;
 
   for (i = 0; i < G_N_ELEMENTS (mapping); i++)
     {
-      if (g_str_has_prefix (script->menu_path, mapping[i].old))
+      if (g_str_has_prefix (menu_path, mapping[i].old))
         {
-          const gchar *suffix = script->menu_path + strlen (mapping[i].old);
-          gchar       *tmp;
+          const gchar *suffix = menu_path + strlen (mapping[i].old);
 
           if (! *suffix == '/')
             continue;
 
-          tmp = g_strconcat (mapping[i].new, suffix, NULL);
-
-          g_free (script->menu_path);
-          script->menu_path = tmp;
-
-          break;
+          return g_strconcat (mapping[i].new, suffix, NULL);
         }
     }
+
+  return NULL;
 }
 
 static gint
@@ -1351,56 +880,12 @@ script_fu_menu_compare (gconstpointer a,
                                gettext (menu_b->menu_path));
 
       if (retval == 0 &&
-          menu_a->script->menu_path && menu_b->script->menu_path)
+          menu_a->script->menu_label && menu_b->script->menu_label)
         {
-          retval = g_utf8_collate (gettext (menu_a->script->menu_path),
-                                   gettext (menu_b->script->menu_path));
+          retval = g_utf8_collate (gettext (menu_a->script->menu_label),
+                                   gettext (menu_b->script->menu_label));
         }
     }
 
   return retval;
 }
-
-/*
- * Escapes the special characters '\b', '\f', '\n', '\r', '\t', '\' and '"'
- * in the string source by inserting a '\' before them.
- */
-gchar *
-script_fu_strescape (const gchar *source)
-{
-  const guchar *p;
-  gchar        *dest;
-  gchar        *q;
-
-  g_return_val_if_fail (source != NULL, NULL);
-
-  p = (const guchar *) source;
-
-  /* Each source byte needs maximally two destination chars */
-  q = dest = g_malloc (strlen (source) * 2 + 1);
-
-  while (*p)
-    {
-      switch (*p)
-        {
-        case '\b':
-        case '\f':
-        case '\n':
-        case '\r':
-        case '\t':
-        case '\\':
-        case '"':
-          *q++ = '\\';
-          /* fallthrough */
-        default:
-          *q++ = *p;
-          break;
-        }
-
-      p++;
-    }
-
-  *q = 0;
-
-  return dest;
-}
diff --git a/tiny-fu/tiny-fu-scripts.h b/tiny-fu/tiny-fu-scripts.h
index d3d685b..07f5030 100644
--- a/tiny-fu/tiny-fu-scripts.h
+++ b/tiny-fu/tiny-fu-scripts.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,20 +12,18 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_SCRIPTS_H__
 #define __SCRIPT_FU_SCRIPTS_H__
 
 
-void       script_fu_find_scripts  (const gchar *path);
-pointer    script_fu_add_script    (scheme *sc, pointer a);
-pointer    script_fu_add_menu      (scheme *sc, pointer a);
-void       script_fu_error_msg     (const gchar *command,
-                                    const gchar *msg);
-gchar   * script_fu_strescape      (const gchar *source);
+void      script_fu_find_scripts  (const gchar *path);
+pointer   script_fu_add_script    (scheme      *sc,
+                                   pointer      a);
+pointer   script_fu_add_menu      (scheme      *sc,
+                                   pointer      a);
 
 
 #endif /*  __SCRIPT_FU_SCRIPTS__  */
diff --git a/tiny-fu/tiny-fu-server.c b/tiny-fu/tiny-fu-server.c
index 822a3c2..d22a3b2 100644
--- a/tiny-fu/tiny-fu-server.c
+++ b/tiny-fu/tiny-fu-server.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -36,7 +35,18 @@
 #include <glib.h>
 
 #ifdef G_OS_WIN32
+#define _WIN32_WINNT 0x0502
 #include <winsock2.h>
+#include <ws2tcpip.h>
+
+typedef short sa_family_t;  /* Not defined by winsock */
+
+#ifndef AI_ADDRCONFIG
+/* Missing from mingw headers, but value is publicly documented
+ * on http://msdn.microsoft.com/en-us/library/ms737530%28v=VS.85%29.aspx
+ */
+#define AI_ADDRCONFIG 0x0400
+#endif
 #include <libgimpbase/gimpwin32-io.h>
 #else
 #include <sys/socket.h>
@@ -108,7 +118,7 @@
 #define RSP_LEN_L_BYTE  3
 
 /*
- *  Local Structures
+ *  Local Types
  */
 
 typedef struct
@@ -129,6 +139,15 @@ typedef struct
   gboolean   run;
 } ServerInterface;
 
+typedef union
+{
+  sa_family_t              family;
+  struct sockaddr_storage  ss;
+  struct sockaddr          sa;
+  struct sockaddr_in       sa_in;
+  struct sockaddr_in6      sa_in6;
+} sa_union;
+
 /*
  *  Local Functions
  */
@@ -137,7 +156,8 @@ static void      server_start       (gint         port,
                                      const gchar *logfile);
 static gboolean  execute_command    (SFCommand   *cmd);
 static gint      read_from_client   (gint         filedes);
-static gint      make_socket        (guint        port);
+static gint      make_socket        (const struct addrinfo
+                                                 *ai);
 static void      server_log         (const gchar *format,
                                      ...) G_GNUC_PRINTF (1, 2);
 static void      server_quit        (void);
@@ -151,7 +171,10 @@ static void      print_socket_api_error (const gchar *api_name);
 /*
  *  Local variables
  */
-static gint         server_sock;
+static gint         server_socks[2],
+                    server_socks_used = 0;
+static const gint   server_socks_len = sizeof (server_socks) /
+                                       sizeof (server_socks[0]);
 static GList       *command_queue   = NULL;
 static gint         queue_length    = 0;
 static gint         request_no      = 0;
@@ -199,7 +222,8 @@ script_fu_server_run (const gchar      *name,
   GimpRunMode        run_mode;
 
   run_mode = params[0].data.d_int32;
-  set_run_mode_constant (run_mode);
+
+  ts_set_run_mode (run_mode);
 
   switch (run_mode)
     {
@@ -223,7 +247,7 @@ script_fu_server_run (const gchar      *name,
 
     case GIMP_RUN_WITH_LAST_VALS:
       status = GIMP_PDB_CALLING_ERROR;
-      g_warning ("Script-Fu server does not handle \"GIMP_RUN_WITH_LAST_VALS\"");
+      g_warning ("Tiny-Fu server does not handle \"GIMP_RUN_WITH_LAST_VALS\"");
 
     default:
       break;
@@ -284,6 +308,7 @@ script_fu_server_listen (gint timeout)
   struct timeval  tv;
   struct timeval *tvp = NULL;
   SELECT_MASK     fds;
+  gint            sockno;
 
   /*  Set time struct  */
   if (timeout)
@@ -294,7 +319,10 @@ script_fu_server_listen (gint timeout)
     }
 
   FD_ZERO (&fds);
-  FD_SET (server_sock, &fds);
+  for (sockno = 0; sockno < server_socks_used; sockno++)
+    {
+      FD_SET (server_socks[sockno], &fds);
+    }
   g_hash_table_foreach (clients, script_fu_server_add_fd, &fds);
 
   /* Block until input arrives on one or more active sockets
@@ -306,15 +334,23 @@ script_fu_server_listen (gint timeout)
       return;
     }
 
-  /* Service the server socket if it has input pending. */
-  if (FD_ISSET (server_sock, &fds))
+  /* Service the server sockets if any has input pending. */
+  for (sockno = 0; sockno < server_socks_used; sockno++)
     {
-      struct sockaddr_in  clientname;
+      sa_union                 client;
+      gchar                    clientname[NI_MAXHOST];
 
       /* Connection request on original socket. */
-      guint size = sizeof (clientname);
-      gint  new  = accept (server_sock,
-                           (struct sockaddr *) &clientname, &size);
+      guint                    size = sizeof (client);
+      gint                     new;
+      guint                    portno;
+
+      if (! FD_ISSET (server_socks[sockno], &fds))
+        {
+          continue;
+        }
+
+      new = accept (server_socks[sockno], &(client.sa), &size);
 
       if (new < 0)
         {
@@ -323,13 +359,32 @@ script_fu_server_listen (gint timeout)
         }
 
       /*  Associate the client address with the socket  */
-      g_hash_table_insert (clients,
-                           GINT_TO_POINTER (new),
-                           g_strdup (inet_ntoa (clientname.sin_addr)));
+
+      /* If all else fails ... */
+      strncpy (clientname, "(error during host address lookup)", NI_MAXHOST-1);
+
+      /* Lookup address */
+      (void) getnameinfo (&(client.sa), size, clientname, sizeof (clientname),
+                          NULL, 0, NI_NUMERICHOST);
+
+      g_hash_table_insert (clients, GINT_TO_POINTER (new),
+                           g_strdup (clientname));
+
+      /* Determine port number */
+      switch (client.family)
+        {
+          case AF_INET:
+            portno = (guint) g_ntohs (client.sa_in.sin_port);
+            break;
+          case AF_INET6:
+            portno = (guint) g_ntohs (client.sa_in6.sin6_port);
+            break;
+          default:
+            portno = 0;
+        }
 
       server_log ("Server: connect from host %s, port %d.\n",
-                  inet_ntoa (clientname.sin_addr),
-                  (unsigned int) ntohs (clientname.sin_port));
+                  clientname, portno);
     }
 
   /* Service the client sockets. */
@@ -391,18 +446,46 @@ static void
 server_start (gint         port,
               const gchar *logfile)
 {
-  const gchar *progress;
+  struct addrinfo *ai,
+                  *ai_curr;
+  struct addrinfo  hints;
+  gint             e,
+                   sockno;
+  gchar           *port_s;
 
-  /* First of all, create the socket and set it up to accept connections. */
-  /* This may fail if there's a server running on this port already.      */
-  server_sock = make_socket (port);
+  const gchar     *progress;
 
-  if (listen (server_sock, 5) < 0)
+  memset (&hints, 0, sizeof (hints));
+  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+  hints.ai_socktype = SOCK_STREAM;
+
+  port_s = g_strdup_printf ("%d", port);
+  e = getaddrinfo (NULL, port_s, &hints, &ai);
+  g_free (port_s);
+
+  if (e != 0)
     {
-      print_socket_api_error ("listen");
+      g_printerr ("getaddrinfo: %s", gai_strerror (e));
       return;
     }
 
+  for (ai_curr = ai, sockno = 0;
+       ai_curr != NULL && sockno < server_socks_len;
+       ai_curr = ai_curr->ai_next, sockno++)
+    {
+      /* Create the socket and set it up to accept connections.          */
+      /* This may fail if there's a server running on this port already. */
+      server_socks[sockno] = make_socket (ai_curr);
+
+      if (listen (server_socks[sockno], 5) < 0)
+        {
+          print_socket_api_error ("listen");
+          return;
+        }
+    }
+
+  server_socks_used = sockno;
+
   /*  Setup up the server log file  */
   if (logfile && *logfile)
     server_log_file = g_fopen (logfile, "a");
@@ -418,7 +501,7 @@ server_start (gint         port,
 
   progress = server_progress_install ();
 
-  server_log ("Script-Fu server initialized and listening...\n");
+  server_log ("Tiny-Fu server initialized and listening...\n");
 
   /*  Loop until the server is finished  */
   while (! script_fu_done)
@@ -450,17 +533,17 @@ server_start (gint         port,
 static gboolean
 execute_command (SFCommand *cmd)
 {
-  guchar       buffer[RESPONSE_HEADER];
-  GString     *response;
-  time_t       clock1;
-  time_t       clock2;
-  gboolean     error;
-  gint         i;
+  guchar    buffer[RESPONSE_HEADER];
+  GString  *response;
+  time_t    clock1;
+  time_t    clock2;
+  gboolean  error;
+  gint      i;
 
   server_log ("Processing request #%d\n", cmd->request_no);
   time (&clock1);
 
-  response = g_string_new ("");
+  response = g_string_new (NULL);
   ts_register_output_func (ts_gstring_output_func, response);
 
   /*  run the command  */
@@ -541,7 +624,7 @@ read_from_client (gint filedes)
 
   if (buffer[MAGIC_BYTE] != MAGIC)
     {
-      server_log ("Error in script-fu command transmission.\n");
+      server_log ("Error in tiny-fu command transmission.\n");
       return -1;
     }
 
@@ -591,11 +674,10 @@ read_from_client (gint filedes)
 }
 
 static gint
-make_socket (guint port)
+make_socket (const struct addrinfo *ai)
 {
-  struct sockaddr_in name;
-  gint               sock;
-  gint               v = 1;
+  gint                    sock;
+  gint                    v = 1;
 
   /*  Win32 needs the winsock library initialized.  */
 #ifdef G_OS_WIN32
@@ -619,7 +701,7 @@ make_socket (guint port)
 #endif
 
   /* Create the socket. */
-  sock = socket (PF_INET, SOCK_STREAM, 0);
+  sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
   if (sock < 0)
     {
       print_socket_api_error ("socket");
@@ -628,12 +710,20 @@ make_socket (guint port)
 
   setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
 
-  /* Give the socket a name. */
-  name.sin_family      = AF_INET;
-  name.sin_port        = htons (port);
-  name.sin_addr.s_addr = htonl (INADDR_ANY);
+#ifdef IPV6_V6ONLY
+  /* Only listen on IPv6 addresses, otherwise bind() will fail. */
+  if (ai->ai_family == AF_INET6)
+    {
+      v = 1;
+      if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
+        {
+          print_socket_api_error ("setsockopt");
+          gimp_quit();
+        }
+    }
+#endif
 
-  if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
+  if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0)
     {
       print_socket_api_error ("bind");
       gimp_quit ();
@@ -671,7 +761,12 @@ script_fu_server_shutdown_fd (gpointer key,
 static void
 server_quit (void)
 {
-  CLOSESOCKET (server_sock);
+  gint sockno;
+
+  for (sockno = 0; sockno < server_socks_used; sockno++)
+    {
+      CLOSESOCKET (server_socks[sockno]);
+    }
 
   if (clients)
     {
@@ -707,11 +802,11 @@ server_interface (void)
 
   INIT_I18N();
 
-  gimp_ui_init ("script-fu", FALSE);
+  gimp_ui_init ("tiny-fu", FALSE);
 
-  dlg = gimp_dialog_new (_("Script-Fu Server Options"), "script-fu",
+  dlg = gimp_dialog_new (_("Tiny-Fu Server Options"), "gimp-tiny-fu",
                          NULL, 0,
-                         gimp_standard_help_func, "plug-in-script-fu-server",
+                         gimp_standard_help_func, "plug-in-tiny-fu-server",
 
                          GTK_STOCK_CANCEL,   GTK_RESPONSE_CANCEL,
                          _("_Start Server"), GTK_RESPONSE_OK,
@@ -735,7 +830,7 @@ server_interface (void)
   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
                       table, FALSE, FALSE, 0);
 
   /*  The server port  */
diff --git a/tiny-fu/tiny-fu-server.h b/tiny-fu/tiny-fu-server.h
index d268a2d..dae6d1b 100644
--- a/tiny-fu/tiny-fu-server.h
+++ b/tiny-fu/tiny-fu-server.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_SERVER_H__
diff --git a/tiny-fu/tiny-fu-text-console.c b/tiny-fu/tiny-fu-text-console.c
index 05629cf..e02ad6f 100644
--- a/tiny-fu/tiny-fu-text-console.c
+++ b/tiny-fu/tiny-fu-text-console.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -41,13 +40,17 @@ script_fu_text_console_run (const gchar      *name,
 {
   static GimpParam  values[1];
 
-  /*  Enable Script-Fu output  */
+  /*  Enable Tiny-Fu output  */
   ts_register_output_func (ts_stdout_output_func, NULL);
 
   ts_print_welcome ();
 
+  gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_PLUGIN);
+
   /*  Run the interface  */
-  ts_interpret_stdin();
+  ts_interpret_stdin ();
+
+  gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_INTERNAL);
 
   values[0].type          = GIMP_PDB_STATUS;
   values[0].data.d_status = GIMP_PDB_SUCCESS;
diff --git a/tiny-fu/tiny-fu-text-console.h b/tiny-fu/tiny-fu-text-console.h
index 3ab564c..7b19a02 100644
--- a/tiny-fu/tiny-fu-text-console.h
+++ b/tiny-fu/tiny-fu-text-console.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,19 +12,18 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_TEXT_CONSOLE_H__
 #define __SCRIPT_FU_TEXT_CONSOLE_H__
 
 
-void   script_fu_text_console_run (const gchar      *name,
-                                  gint              nparams,
-                                  const GimpParam  *params,
-                                  gint             *nreturn_vals,
-                                  GimpParam       **return_vals);
+void  script_fu_text_console_run (const gchar      *name,
+                                  gint              nparams,
+                                  const GimpParam  *params,
+                                  gint             *nreturn_vals,
+                                  GimpParam       **return_vals);
 
 
-#endif /*  __SCRIPT_FU_TEXT_CONSOLE__  */
+#endif /*  __SCRIPT_FU_TEXT_CONSOLE_H__  */
diff --git a/tiny-fu/tiny-fu-types.h b/tiny-fu/tiny-fu-types.h
index 1dc2cf7..f63e66b 100644
--- a/tiny-fu/tiny-fu-types.h
+++ b/tiny-fu/tiny-fu-types.h
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __SCRIPT_FU_TYPES_H__
@@ -50,14 +49,14 @@ typedef struct
 
 typedef struct
 {
-  GSList  *list;
-  gint     history;
+  GSList *list;
+  gint    history;
 } SFOption;
 
 typedef struct
 {
-  gchar   *type_name;
-  gint     history;
+  gchar *type_name;
+  gint   history;
 } SFEnum;
 
 typedef union
@@ -84,19 +83,24 @@ typedef union
 
 typedef struct
 {
-  gchar         *name;
-  gchar         *menu_path;
-  gchar         *blurb;
-  gchar         *author;
-  gchar         *copyright;
-  gchar         *date;
-  gchar         *img_types;
-  gint           num_args;
-  SFArgType     *arg_types;
-  gchar        **arg_labels;
-  SFArgValue    *arg_defaults;
-  SFArgValue    *arg_values;
-  GimpParamDef  *args;     /*  used only temporary until installed  */
+  SFArgType   type;
+  gchar      *label;
+  SFArgValue  default_value;
+  SFArgValue  value;
+} SFArg;
+
+typedef struct
+{
+  gchar        *name;
+  gchar        *menu_label;
+  gchar        *blurb;
+  gchar        *author;
+  gchar        *copyright;
+  gchar        *date;
+  gchar        *image_types;
+
+  gint          n_args;
+  SFArg        *args;
 } SFScript;
 
 
diff --git a/tiny-fu/tiny-fu-utils.c b/tiny-fu/tiny-fu-utils.c
new file mode 100644
index 0000000..c0bced4
--- /dev/null
+++ b/tiny-fu/tiny-fu-utils.c
@@ -0,0 +1,69 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "tiny-fu-utils.h"
+
+
+/*
+ * Escapes the special characters '\b', '\f', '\n', '\r', '\t', '\' and '"'
+ * in the string source by inserting a '\' before them.
+ */
+gchar *
+script_fu_strescape (const gchar *source)
+{
+  const guchar *p;
+  gchar        *dest;
+  gchar        *q;
+
+  g_return_val_if_fail (source != NULL, NULL);
+
+  p = (const guchar *) source;
+
+  /* Each source byte needs maximally two destination chars */
+  q = dest = g_malloc (strlen (source) * 2 + 1);
+
+  while (*p)
+    {
+      switch (*p)
+        {
+        case '\b':
+        case '\f':
+        case '\n':
+        case '\r':
+        case '\t':
+        case '\\':
+        case '"':
+          *q++ = '\\';
+          /* fallthrough */
+        default:
+          *q++ = *p;
+          break;
+        }
+
+      p++;
+    }
+
+  *q = 0;
+
+  return dest;
+}
diff --git a/tiny-fu/tiny-fu-utils.h b/tiny-fu/tiny-fu-utils.h
new file mode 100644
index 0000000..c84f8fc
--- /dev/null
+++ b/tiny-fu/tiny-fu-utils.h
@@ -0,0 +1,25 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_UTILS_H__
+#define __SCRIPT_FU_UTILS_H__
+
+
+gchar * script_fu_strescape (const gchar *source);
+
+
+#endif /*  __SCRIPT_FU_UTILS__  */
diff --git a/tiny-fu/tiny-fu.c b/tiny-fu/tiny-fu.c
index fbaa473..9452068 100644
--- a/tiny-fu/tiny-fu.c
+++ b/tiny-fu/tiny-fu.c
@@ -1,9 +1,9 @@
 /* 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
+ * 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 2 of the License, or
+ * 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,
@@ -12,8 +12,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -36,12 +35,13 @@
 #include "tiny-fu-types.h"
 
 #include "tiny-fu-console.h"
+#include "tiny-fu-eval.h"
 #include "tiny-fu-interface.h"
 #include "tiny-fu-scripts.h"
 #include "tiny-fu-server.h"
 #include "tiny-fu-text-console.h"
 
-#include "ts-wrapper.h"
+#include "scheme-wrapper.h"
 
 #include "tiny-fu-intl.h"
 
@@ -78,12 +78,13 @@ const GimpPlugInInfo PLUG_IN_INFO =
 EXPORT void
 init_tiny_fu (scheme *sc)
 {
+    printf ("Loaded Tiny-Fu extension\n");
+
     sc->vptr->scheme_define (sc, sc->global_env,
                              sc->vptr->mk_symbol(sc,"tiny-fu-init"),
                              sc->vptr->mk_foreign_func(sc, tiny_fu_main_init));
 }
 
-
 /* The parameters passed to TinyScheme can be found in *args*. */
 pointer
 tiny_fu_main_init (scheme *sc, pointer args)
@@ -98,11 +99,11 @@ tiny_fu_main_init (scheme *sc, pointer args)
     argv = g_new (char *, argc);
 
     for (i = 0; i < argc; ++i)
-      {
-        argv[i] = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (args)));
+       {
+         argv[i] = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (args)));
 
-        args = sc->vptr->pair_cdr (args);
-      }
+         args = sc->vptr->pair_cdr (args);
+       }
 
     i = gimp_main (&PLUG_IN_INFO, argc, argv);
 
@@ -116,37 +117,35 @@ tiny_fu_main_init (scheme *sc, pointer args)
     return sc->F;
 }
 
-
 static void
 script_fu_query (void)
 {
-#if 0
   static const GimpParamDef console_args[] =
   {
-    { GIMP_PDB_INT32,  "run-mode", "Interactive, [non-interactive]" }
+    { GIMP_PDB_INT32,  "run-mode", "The run mode { RUN-INTERACTIVE (0) }" }
   };
 
   static const GimpParamDef textconsole_args[] =
   {
-    { GIMP_PDB_INT32,  "run-mode", "Interactive, [non-interactive]" }
+    { GIMP_PDB_INT32,  "run-mode", "The run mode { RUN-INTERACTIVE (0) }" }
   };
 
   static const GimpParamDef eval_args[] =
   {
-    { GIMP_PDB_INT32,  "run-mode", "[Interactive], non-interactive" },
-    { GIMP_PDB_STRING, "code",     "The code to evaluate" }
+    { GIMP_PDB_INT32,  "run-mode", "The run mode { RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_STRING, "code",     "The code to evaluate"                    }
   };
 
   static const GimpParamDef server_args[] =
   {
-    { GIMP_PDB_INT32,  "run-mode", "[Interactive], non-interactive" },
+    { GIMP_PDB_INT32,  "run-mode", "The run mode { RUN-NONINTERACTIVE (1) }"  },
     { GIMP_PDB_INT32,  "port",     "The port on which to listen for requests" },
-    { GIMP_PDB_STRING, "logfile",  "The file to log server activity to" }
+    { GIMP_PDB_STRING, "logfile",  "The file to log server activity to"       }
   };
 
-  gimp_plugin_domain_register (GETTEXT_PACKAGE "-script-fu", NULL);
+  gimp_plugin_domain_register (GETTEXT_PACKAGE "-tiny-fu", NULL);
 
-  gimp_install_procedure ("extension-script-fu",
+  gimp_install_procedure ("extension-tiny-fu",
                           "A scheme interpreter for scripting GIMP operations",
                           "More help here later",
                           "Spencer Kimball & Peter Mattis",
@@ -157,24 +156,24 @@ script_fu_query (void)
                           GIMP_EXTENSION,
                           0, 0, NULL, NULL);
 
-  gimp_install_procedure ("plug-in-script-fu-console",
-                          N_("Interactive console for Script-Fu development"),
+  gimp_install_procedure ("plug-in-tiny-fu-console",
+                          N_("Interactive console for Tiny-Fu development"),
                           "Provides an interface which allows interactive "
                                       "scheme development.",
                           "Spencer Kimball & Peter Mattis",
                           "Spencer Kimball & Peter Mattis",
                           "1997",
-                          N_("Script-Fu _Console"),
+                          N_("_Console"),
                           NULL,
                           GIMP_PLUGIN,
                           G_N_ELEMENTS (console_args), 0,
                           console_args, NULL);
 
-  gimp_plugin_menu_register ("plug-in-script-fu-console",
-                             "<Toolbox>/Xtns/Languages/Script-Fu");
+  gimp_plugin_menu_register ("plug-in-tiny-fu-console",
+                             "<Image>/Filters/Languages/Tiny-Fu");
 
-  gimp_install_procedure ("plug-in-script-fu-text-console",
-                          "Provides a text console mode for script-fu "
+  gimp_install_procedure ("plug-in-tiny-fu-text-console",
+                          "Provides a text console mode for tiny-fu "
                           "development",
                           "Provides an interface which allows interactive "
                           "scheme development.",
@@ -187,9 +186,9 @@ script_fu_query (void)
                           G_N_ELEMENTS (textconsole_args), 0,
                           textconsole_args, NULL);
 
-  gimp_install_procedure ("plug-in-script-fu-server",
-                          N_("Server for remote Script-Fu operation"),
-                          "Provides a server for remote script-fu operation",
+  gimp_install_procedure ("plug-in-tiny-fu-server",
+                          N_("Server for remote Tiny-Fu operation"),
+                          "Provides a server for remote tiny-fu operation",
                           "Spencer Kimball & Peter Mattis",
                           "Spencer Kimball & Peter Mattis",
                           "1997",
@@ -199,10 +198,10 @@ script_fu_query (void)
                           G_N_ELEMENTS (server_args), 0,
                           server_args, NULL);
 
-  gimp_plugin_menu_register ("plug-in-script-fu-server",
-                             "<Toolbox>/Xtns/Languages/Script-Fu");
+  gimp_plugin_menu_register ("plug-in-tiny-fu-server",
+                             "<Image>/Filters/Languages/Tiny-Fu");
 
-  gimp_install_procedure ("plug-in-script-fu-eval",
+  gimp_install_procedure ("plug-in-tiny-fu-eval",
                           "Evaluate scheme code",
                           "Evaluate the code under the scheme interpreter "
                                       "(primarily for batch mode)",
@@ -214,7 +213,6 @@ script_fu_query (void)
                           GIMP_PLUGIN,
                           G_N_ELEMENTS (eval_args), 0,
                           eval_args, NULL);
-#endif
 }
 
 static void
@@ -233,7 +231,7 @@ script_fu_run (const gchar      *name,
   /*  Determine before we allow scripts to register themselves
    *   whether this is the base, automatically installed script-fu extension
    */
-  if (strcmp (name, "extension-script-fu") == 0)
+  if (strcmp (name, "extension-tiny-fu") == 0)
     {
       /*  Setup auxillary temporary procedures for the base extension  */
       script_fu_extension_init ();
@@ -248,17 +246,17 @@ script_fu_run (const gchar      *name,
     }
 
   if (param != NULL)
-      set_run_mode_constant ((GimpRunMode)param[0].data.d_int32);
+    ts_set_run_mode ((GimpRunMode) param[0].data.d_int32);
 
   /*  Load all of the available scripts  */
   script_fu_find_scripts (path);
 
   g_free (path);
 
-  if (strcmp (name, "extension-script-fu") == 0)
+  if (strcmp (name, "extension-tiny-fu") == 0)
     {
       /*
-       *  The main script-fu extension.
+       *  The main tiny-fu extension.
        */
 
       static GimpParam  values[1];
@@ -277,34 +275,34 @@ script_fu_run (const gchar      *name,
       values[0].type          = GIMP_PDB_STATUS;
       values[0].data.d_status = GIMP_PDB_SUCCESS;
     }
-  else if (strcmp (name, "plug-in-script-fu-text-console") == 0)
+  else if (strcmp (name, "plug-in-tiny-fu-text-console") == 0)
     {
       /*
-       *  The script-fu text console for interactive Scheme development
+       *  The tiny-fu text console for interactive Scheme development
        */
 
       script_fu_text_console_run (name, nparams, param,
                                   nreturn_vals, return_vals);
     }
-  else if (strcmp (name, "plug-in-script-fu-console") == 0)
+  else if (strcmp (name, "plug-in-tiny-fu-console") == 0)
     {
       /*
-       *  The script-fu console for interactive Scheme development
+       *  The tiny-fu console for interactive Scheme development
        */
 
       script_fu_console_run (name, nparams, param,
                              nreturn_vals, return_vals);
     }
-  else if (strcmp (name, "plug-in-script-fu-server") == 0)
+  else if (strcmp (name, "plug-in-tiny-fu-server") == 0)
     {
       /*
-       *  The script-fu server for remote operation
+       *  The tiny-fu server for remote operation
        */
 
       script_fu_server_run (name, nparams, param,
                             nreturn_vals, return_vals);
     }
-  else if (strcmp (name, "plug-in-script-fu-eval") == 0)
+  else if (strcmp (name, "plug-in-tiny-fu-eval") == 0)
     {
       /*
        *  A non-interactive "console" (for batch mode)
@@ -321,7 +319,7 @@ script_fu_search_path (void)
   gchar  *path_str;
   gchar  *path  = NULL;
 
-  path_str = gimp_gimprc_query ("script-fu-path");
+  path_str = gimp_gimprc_query ("tiny-fu-path");
 
   if (path_str)
     {
@@ -333,7 +331,7 @@ script_fu_search_path (void)
 
       if (! path)
         {
-          g_warning ("Can't convert script-fu-path to filesystem encoding: %s",
+          g_warning ("Can't convert tiny-fu-path to filesystem encoding: %s",
                      error->message);
           g_error_free (error);
         }
@@ -350,60 +348,36 @@ script_fu_extension_init (void)
     { GIMP_PDB_INT32, "run-mode", "[Interactive], non-interactive" }
   };
 
-  gimp_plugin_menu_branch_register ("<Toolbox>/Help", N_("_GIMP Online"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Help", N_("_User Manual"));
+  gimp_plugin_menu_branch_register ("<Image>/Help", N_("_GIMP Online"));
+  gimp_plugin_menu_branch_register ("<Image>/Help", N_("_User Manual"));
 
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns/Languages",
-                                    N_("_Script-Fu"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
+  gimp_plugin_menu_branch_register ("<Image>/Filters/Languages",
+                                    N_("_Tiny-Fu"));
+  gimp_plugin_menu_branch_register ("<Image>/Filters/Languages/Tiny-Fu",
+                                    N_("_Test"));
+
+  gimp_plugin_menu_branch_register ("<Image>/File/Create",
                                     N_("_Buttons"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
+  gimp_plugin_menu_branch_register ("<Image>/File/Create",
                                     N_("_Logos"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
-                                    N_("_Misc"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
+  gimp_plugin_menu_branch_register ("<Image>/File/Create",
                                     N_("_Patterns"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns/Languages/Script-Fu",
-                                    N_("_Test"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
-                                    N_("_Utilities"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns",
+
+  gimp_plugin_menu_branch_register ("<Image>/File/Create",
                                     N_("_Web Page Themes"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns/Web Page Themes",
+  gimp_plugin_menu_branch_register ("<Image>/File/Create/Web Page Themes",
                                     N_("_Alien Glow"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns/Web Page Themes",
+  gimp_plugin_menu_branch_register ("<Image>/File/Create/Web Page Themes",
                                     N_("_Beveled Pattern"));
-  gimp_plugin_menu_branch_register ("<Toolbox>/Xtns/Web Page Themes",
+  gimp_plugin_menu_branch_register ("<Image>/File/Create/Web Page Themes",
                                     N_("_Classic.Gimp.Org"));
 
   gimp_plugin_menu_branch_register ("<Image>/Filters",
                                     N_("Alpha to _Logo"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("An_imation"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters/Animation",
-                                    N_("_Animators"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Artistic"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Blur"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Decor"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Effects"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("En_hance"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Light and Shadow"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters/Light and Shadow",
-                                    N_("S_hadow"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters",
-                                    N_("_Render"));
-  gimp_plugin_menu_branch_register ("<Image>/Filters/Effects",
-                                    N_("_Alchemy"));
 
-  gimp_install_temp_proc ("script-fu-refresh",
-                          N_("Re-read all available Script-Fu scripts"),
-                          "Re-read all available Script-Fu scripts",
+  gimp_install_temp_proc ("tiny-fu-refresh",
+                          N_("Re-read all available Tiny-Fu scripts"),
+                          "Re-read all available Tiny-Fu scripts",
                           "Spencer Kimball & Peter Mattis",
                           "Spencer Kimball & Peter Mattis",
                           "1997",
@@ -414,8 +388,8 @@ script_fu_extension_init (void)
                           args, NULL,
                           script_fu_refresh_proc);
 
-  gimp_plugin_menu_register ("script-fu-refresh",
-                             "<Toolbox>/Xtns/Languages/Script-Fu");
+  gimp_plugin_menu_register ("tiny-fu-refresh",
+                             "<Image>/Filters/Languages/Tiny-Fu");
 }
 
 static void
@@ -431,8 +405,8 @@ script_fu_refresh_proc (const gchar      *name,
   if (script_fu_interface_is_active ())
     {
       g_message (_("You can not use \"Refresh Scripts\" while a "
-                   "Script-Fu dialog box is open.  Please close "
-                   "all Script-Fu windows and try again."));
+                   "Tiny-Fu dialog box is open.  Please close "
+                   "all Tiny-Fu windows and try again."));
 
       status = GIMP_PDB_EXECUTION_ERROR;
     }
diff --git a/tinyscheme/scheme.c b/tinyscheme/scheme.c
index 39c42f4..75a9af7 100644
--- a/tinyscheme/scheme.c
+++ b/tinyscheme/scheme.c
@@ -101,7 +101,7 @@ ts_output_string (TsOutputType  type,
  *  Basic memory allocation units
  */
 
-#define banner "TinyScheme 1.40 (with UTF-8 support)"
+#define banner "TinyScheme 1.40 (with UTF-8 support)\n"
 
 #include <string.h>
 #include <stdlib.h>
@@ -5195,8 +5195,8 @@ int main(int argc, char **argv) {
   if(argc==1) {
     printf(banner);
   }
-  if(argc==2 && strcmp(argv[1],"-?")==0) {
-    printf("Usage: tinyscheme -?\n");
+  if(argc==2 && strcmp(argv[1],"-h")==0) {
+    printf("Usage: tinyscheme [-h]\n");
     printf("or:    tinyscheme [<file1> <file2> ...]\n");
     printf("followed by\n");
     printf("          -1 <file> [<arg1> <arg2> ...]\n");
@@ -5214,24 +5214,18 @@ int main(int argc, char **argv) {
 #if USE_DL
   scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
 #endif
-  argv++;
-  if(g_access(file_name,0)!=0) {
-    char *p=getenv("TINYSCHEMEINIT");
-    if(p!=0) {
-      file_name=p;
-    }
-  }
 
-#if 1
-  if (argc > 2 && strcmp (argv[1], "-gimp") == 0)
+  if (argc == 7 && strcmp (argv[2], "-gimp") == 0)
   {
     pointer args = sc.NIL;
+    char *s;
     int i;
 
-    chdir (getenv("TINYFUPATH"));
+    s = g_strdup_printf ("%s/%s", getenv("TINYFUPATH"), "tiny_fu");
+    scm_load_ext(&sc, mk_symbol (&sc, s));  //Load tiny-fu extension
+    g_free (s);
 
-    --argc; /* argv was incremented above */
-    for (i = 0; i < argc; ++i)
+    for (i = 1; i < argc; ++i)
       {
         pointer value = mk_string (&sc, argv[i]);
         args = cons (&sc, value, args);
@@ -5239,38 +5233,38 @@ int main(int argc, char **argv) {
     args = reverse_in_place (&sc, sc.NIL, args);
     scheme_define (&sc, sc.global_env, mk_symbol (&sc, "*args*"), args);
 
-    fin = fopen (file_name, "rb");
-    if (fin == 0)
-        fprintf (stderr, "Could not open file %s\n", file_name);
-    else
-      {
-        scheme_load_file (&sc, fin);
-        fclose (fin);
-      }
+    scheme_load_string(&sc, "(tiny-fu-init *args*)");
 
-    fin = fopen (argv[0], "rb");
+    fin = fopen (argv[1], "rb");
     if (fin == 0)
-        fprintf (stderr, "Could not open file %s\n", argv[0]);
+        fprintf (stderr, "Could not open file %s\n", argv[1]);
     else
       {
         scheme_load_file (&sc, fin);
         fclose (fin);
       }
   }
-  else
-#endif
+  else {
+
+  //Start of original standalone initialization
+  argv++;
+  if(g_access(file_name,0)!=0) {
+    char *p=getenv("TINYSCHEMEINIT");
+    if(p!=0) {
+      file_name=p;
+    }
+  }
   do {
     if(strcmp(file_name,"-")==0) {
       fin=stdin;
-    } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0 ||
-              strcmp(*argv,"-gimp")==0) {
+    } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
       pointer args=sc.NIL;
       isfile=file_name[1]=='1';
       file_name=*argv++;
       if(strcmp(file_name,"-")==0) {
         fin=stdin;
       } else if(isfile) {
-        fin=g_fopen(file_name,"r");
+        fin=g_fopen(file_name,"rb");
       }
       for(;*argv;argv++) {
         pointer value=mk_string(&sc,*argv);
@@ -5280,7 +5274,7 @@ int main(int argc, char **argv) {
       scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
 
     } else {
-      fin=g_fopen(file_name,"r");
+      fin=g_fopen(file_name,"rb");
     }
     if(isfile && fin==0) {
       fprintf(stderr,"Could not open file %s\n",file_name);
@@ -5304,6 +5298,10 @@ int main(int argc, char **argv) {
   if(argc==1) {
     scheme_load_named_file(&sc,stdin,0);
   }
+  //End of original standalone initialization
+
+  } //End of else block
+
   retcode=sc.retcode;
   scheme_deinit(&sc);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]