summaryrefslogtreecommitdiffstats
path: root/plug-ins/script-fu
diff options
context:
space:
mode:
Diffstat (limited to 'plug-ins/script-fu')
-rw-r--r--plug-ins/script-fu/Makefile.am117
-rw-r--r--plug-ins/script-fu/Makefile.in1225
-rw-r--r--plug-ins/script-fu/ftx/LICENSE31
-rw-r--r--plug-ins/script-fu/ftx/Makefile.am16
-rw-r--r--plug-ins/script-fu/ftx/Makefile.in912
-rw-r--r--plug-ins/script-fu/ftx/README99
-rw-r--r--plug-ins/script-fu/ftx/ftx-functions.txt119
-rw-r--r--plug-ins/script-fu/ftx/ftx.c415
-rw-r--r--plug-ins/script-fu/ftx/ftx.h2
-rw-r--r--plug-ins/script-fu/ftx/listhome.scm58
-rw-r--r--plug-ins/script-fu/scheme-wrapper.c1671
-rw-r--r--plug-ins/script-fu/scheme-wrapper.h47
-rw-r--r--plug-ins/script-fu/script-fu-console.c703
-rw-r--r--plug-ins/script-fu/script-fu-console.h29
-rw-r--r--plug-ins/script-fu/script-fu-enums.h54
-rw-r--r--plug-ins/script-fu/script-fu-eval.c80
-rw-r--r--plug-ins/script-fu/script-fu-eval.h29
-rw-r--r--plug-ins/script-fu/script-fu-interface.c1070
-rw-r--r--plug-ins/script-fu/script-fu-interface.h28
-rw-r--r--plug-ins/script-fu/script-fu-intl.h43
-rw-r--r--plug-ins/script-fu/script-fu-regex.c179
-rw-r--r--plug-ins/script-fu/script-fu-regex.h25
-rw-r--r--plug-ins/script-fu/script-fu-script.c780
-rw-r--r--plug-ins/script-fu/script-fu-script.h49
-rw-r--r--plug-ins/script-fu/script-fu-scripts.c934
-rw-r--r--plug-ins/script-fu/script-fu-scripts.h29
-rw-r--r--plug-ins/script-fu/script-fu-server.c1113
-rw-r--r--plug-ins/script-fu/script-fu-server.h32
-rw-r--r--plug-ins/script-fu/script-fu-text-console.c60
-rw-r--r--plug-ins/script-fu/script-fu-text-console.h29
-rw-r--r--plug-ins/script-fu/script-fu-types.h107
-rw-r--r--plug-ins/script-fu/script-fu-utils.c69
-rw-r--r--plug-ins/script-fu/script-fu-utils.h25
-rw-r--r--plug-ins/script-fu/script-fu.c385
-rw-r--r--plug-ins/script-fu/scripts/Makefile.am70
-rw-r--r--plug-ins/script-fu/scripts/Makefile.in1044
-rw-r--r--plug-ins/script-fu/scripts/add-bevel.scm202
-rw-r--r--plug-ins/script-fu/scripts/addborder.scm177
-rw-r--r--plug-ins/script-fu/scripts/blend-anim.scm242
-rw-r--r--plug-ins/script-fu/scripts/burn-in-anim.scm243
-rw-r--r--plug-ins/script-fu/scripts/carve-it.scm205
-rw-r--r--plug-ins/script-fu/scripts/chrome-it.scm252
-rw-r--r--plug-ins/script-fu/scripts/circuit.scm143
-rw-r--r--plug-ins/script-fu/scripts/clothify.scm68
-rw-r--r--plug-ins/script-fu/scripts/coffee.scm94
-rw-r--r--plug-ins/script-fu/scripts/contactsheet.scm337
-rw-r--r--plug-ins/script-fu/scripts/copy-visible.scm49
-rw-r--r--plug-ins/script-fu/scripts/difference-clouds.scm80
-rw-r--r--plug-ins/script-fu/scripts/distress-selection.scm122
-rw-r--r--plug-ins/script-fu/scripts/drop-shadow.scm187
-rw-r--r--plug-ins/script-fu/scripts/erase-rows.scm71
-rw-r--r--plug-ins/script-fu/scripts/font-map.scm168
-rw-r--r--plug-ins/script-fu/scripts/fuzzyborder.scm168
-rw-r--r--plug-ins/script-fu/scripts/gimp-online.scm293
-rw-r--r--plug-ins/script-fu/scripts/gradient-example.scm81
-rw-r--r--plug-ins/script-fu/scripts/grid-system.scm95
-rw-r--r--plug-ins/script-fu/scripts/guides-from-selection.scm43
-rw-r--r--plug-ins/script-fu/scripts/guides-new-percent.scm41
-rw-r--r--plug-ins/script-fu/scripts/guides-new.scm40
-rw-r--r--plug-ins/script-fu/scripts/guides-remove-all.scm30
-rw-r--r--plug-ins/script-fu/scripts/images/Makefile.am12
-rw-r--r--plug-ins/script-fu/scripts/images/Makefile.in810
-rw-r--r--plug-ins/script-fu/scripts/images/beavis.jpgbin0 -> 20688 bytes
-rw-r--r--plug-ins/script-fu/scripts/images/texture.jpgbin0 -> 22622 bytes
-rw-r--r--plug-ins/script-fu/scripts/images/texture1.jpgbin0 -> 4256 bytes
-rw-r--r--plug-ins/script-fu/scripts/images/texture2.jpgbin0 -> 4983 bytes
-rw-r--r--plug-ins/script-fu/scripts/images/texture3.jpgbin0 -> 3245 bytes
-rw-r--r--plug-ins/script-fu/scripts/lava.scm135
-rw-r--r--plug-ins/script-fu/scripts/line-nova.scm123
-rw-r--r--plug-ins/script-fu/scripts/mkbrush.scm272
-rw-r--r--plug-ins/script-fu/scripts/old-photo.scm108
-rw-r--r--plug-ins/script-fu/scripts/palette-export.scm402
-rw-r--r--plug-ins/script-fu/scripts/paste-as-brush.scm74
-rw-r--r--plug-ins/script-fu/scripts/paste-as-pattern.scm61
-rw-r--r--plug-ins/script-fu/scripts/perspective-shadow.scm217
-rw-r--r--plug-ins/script-fu/scripts/plug-in-compat.init24
-rw-r--r--plug-ins/script-fu/scripts/predator.scm137
-rw-r--r--plug-ins/script-fu/scripts/reverse-layers.scm53
-rw-r--r--plug-ins/script-fu/scripts/ripply-anim.scm83
-rw-r--r--plug-ins/script-fu/scripts/round-corners.scm149
-rw-r--r--plug-ins/script-fu/scripts/script-fu-compat.init457
-rw-r--r--plug-ins/script-fu/scripts/script-fu-set-cmap.scm64
-rw-r--r--plug-ins/script-fu/scripts/script-fu-util.scm94
-rw-r--r--plug-ins/script-fu/scripts/script-fu.init716
-rw-r--r--plug-ins/script-fu/scripts/select-to-brush.scm144
-rw-r--r--plug-ins/script-fu/scripts/select-to-image.scm89
-rw-r--r--plug-ins/script-fu/scripts/select-to-pattern.scm103
-rw-r--r--plug-ins/script-fu/scripts/selection-round.scm164
-rw-r--r--plug-ins/script-fu/scripts/slide.scm261
-rw-r--r--plug-ins/script-fu/scripts/spinning-globe.scm110
-rw-r--r--plug-ins/script-fu/scripts/spyrogimp.scm352
-rw-r--r--plug-ins/script-fu/scripts/test-sphere.scm307
-rw-r--r--plug-ins/script-fu/scripts/tileblur.scm83
-rw-r--r--plug-ins/script-fu/scripts/ts-helloworld.scm65
-rw-r--r--plug-ins/script-fu/scripts/unsharp-mask.scm84
-rw-r--r--plug-ins/script-fu/scripts/waves-anim.scm110
-rw-r--r--plug-ins/script-fu/scripts/weave.scm415
-rw-r--r--plug-ins/script-fu/scripts/xach-effect.scm142
-rw-r--r--plug-ins/script-fu/tinyscheme/BUILDING139
-rw-r--r--plug-ins/script-fu/tinyscheme/CHANGES326
-rw-r--r--plug-ins/script-fu/tinyscheme/COPYING31
-rw-r--r--plug-ins/script-fu/tinyscheme/Makefile.am26
-rw-r--r--plug-ins/script-fu/tinyscheme/Makefile.in924
-rw-r--r--plug-ins/script-fu/tinyscheme/Manual.txt452
-rw-r--r--plug-ins/script-fu/tinyscheme/MiniSCHEMETribute.txt88
-rw-r--r--plug-ins/script-fu/tinyscheme/README14
-rw-r--r--plug-ins/script-fu/tinyscheme/hack.txt233
-rw-r--r--plug-ins/script-fu/tinyscheme/opdefines.h195
-rw-r--r--plug-ins/script-fu/tinyscheme/scheme-private.h227
-rw-r--r--plug-ins/script-fu/tinyscheme/scheme.c5352
-rw-r--r--plug-ins/script-fu/tinyscheme/scheme.h273
111 files changed, 29809 insertions, 0 deletions
diff --git a/plug-ins/script-fu/Makefile.am b/plug-ins/script-fu/Makefile.am
new file mode 100644
index 0000000..46ad336
--- /dev/null
+++ b/plug-ins/script-fu/Makefile.am
@@ -0,0 +1,117 @@
+## Process this file with automake to produce Makefile.in
+
+if PLATFORM_OSX
+xobjective_c = "-xobjective-c"
+xobjective_cxx = "-xobjective-c++"
+xnone = "-xnone"
+framework_cocoa = -framework Cocoa
+endif
+
+if OS_WIN32
+mwindows = -mwindows
+WINSOCK_LIBS = -lws2_32
+else
+libm = -lm
+endif
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la $(libm)
+
+libtinyscheme=tinyscheme/libtinyscheme.a $(libm)
+libftx=ftx/libftx.a
+
+if HAVE_WINDRES
+include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
+script_fu_RC = script-fu.rc.o
+endif
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir) \
+ -DSTANDALONE=0 \
+ -DUSE_INTERFACE=1 \
+ -DUSE_STRLWR=0
+
+AM_CFLAGS = \
+ $(xobjective_c)
+
+AM_CXXFLAGS = \
+ $(xobjective_cxx)
+
+AM_LDFLAGS = \
+ $(mwindows) \
+ $(framework_cocoa) \
+ $(xnone)
+
+SUBDIRS = tinyscheme ftx scripts
+
+
+libexecdir = $(gimpplugindir)/plug-ins/script-fu
+
+libexec_PROGRAMS = script-fu
+
+script_fu_SOURCES = \
+ script-fu-types.h \
+ script-fu-enums.h \
+ \
+ script-fu.c \
+ script-fu-console.c \
+ script-fu-console.h \
+ script-fu-eval.c \
+ script-fu-eval.h \
+ script-fu-interface.c \
+ script-fu-interface.h \
+ script-fu-text-console.h \
+ script-fu-text-console.c \
+ script-fu-intl.h \
+ script-fu-regex.c \
+ script-fu-regex.h \
+ script-fu-script.c \
+ script-fu-script.h \
+ script-fu-scripts.c \
+ script-fu-scripts.h \
+ script-fu-server.c \
+ script-fu-server.h \
+ script-fu-utils.c \
+ script-fu-utils.h \
+ scheme-wrapper.c \
+ scheme-wrapper.h
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimpmath) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpbase) \
+ $(libtinyscheme) \
+ $(libftx) \
+ $(GTK_LIBS) \
+ $(SOCKET_LIBS) \
+ $(WINSOCK_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(script_fu_RC)
+
+
+# Perform static analysis on all *.scm files and look for usage of
+# deprecated pdb procedures
+check-for-deprecated-procedures-in-script-fu:
+ @echo "Looking for deprecated procedures in *.scm files"
+ @scm_files=`find $(top_srcdir)/plug-ins/script-fu -name "*.scm"`; \
+ deprecated_procs=`$(top_builddir)/app/gimp-$(GIMP_APP_VERSION)$(EXEEXT) --dump-pdb-procedures-deprecated`; \
+ for scm_file in $$scm_files; do \
+ for proc in $$deprecated_procs; do \
+ if grep -Eq "^([^;]*[[:blank:](])?$$proc([[:blank:])]|$$)" $$scm_file; then \
+ echo "$${scm_file} uses deprecated procedure '$${proc}'"; \
+ fi \
+ done \
+ done
diff --git a/plug-ins/script-fu/Makefile.in b/plug-ins/script-fu/Makefile.in
new file mode 100644
index 0000000..493b4f7
--- /dev/null
+++ b/plug-ins/script-fu/Makefile.in
@@ -0,0 +1,1225 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Version resources for Microsoft Windows
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+libexec_PROGRAMS = script-fu$(EXEEXT)
+subdir = plug-ins/script-fu
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(libexecdir)"
+PROGRAMS = $(libexec_PROGRAMS)
+am_script_fu_OBJECTS = script-fu.$(OBJEXT) script-fu-console.$(OBJEXT) \
+ script-fu-eval.$(OBJEXT) script-fu-interface.$(OBJEXT) \
+ script-fu-text-console.$(OBJEXT) script-fu-regex.$(OBJEXT) \
+ script-fu-script.$(OBJEXT) script-fu-scripts.$(OBJEXT) \
+ script-fu-server.$(OBJEXT) script-fu-utils.$(OBJEXT) \
+ scheme-wrapper.$(OBJEXT)
+script_fu_OBJECTS = $(am_script_fu_OBJECTS)
+script_fu_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la \
+ $(am__DEPENDENCIES_1)
+am__DEPENDENCIES_3 = tinyscheme/libtinyscheme.a $(am__DEPENDENCIES_1)
+script_fu_DEPENDENCIES = $(libgimpui) $(libgimpwidgets) \
+ $(libgimpconfig) $(am__DEPENDENCIES_2) $(libgimp) \
+ $(libgimpcolor) $(libgimpbase) $(am__DEPENDENCIES_3) $(libftx) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(script_fu_RC)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/scheme-wrapper.Po \
+ ./$(DEPDIR)/script-fu-console.Po ./$(DEPDIR)/script-fu-eval.Po \
+ ./$(DEPDIR)/script-fu-interface.Po \
+ ./$(DEPDIR)/script-fu-regex.Po ./$(DEPDIR)/script-fu-script.Po \
+ ./$(DEPDIR)/script-fu-scripts.Po \
+ ./$(DEPDIR)/script-fu-server.Po \
+ ./$(DEPDIR)/script-fu-text-console.Po \
+ ./$(DEPDIR)/script-fu-utils.Po ./$(DEPDIR)/script-fu.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(script_fu_SOURCES)
+DIST_SOURCES = $(script_fu_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build/windows/gimprc-plug-ins.rule \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = $(gimpplugindir)/plug-ins/script-fu
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@PLATFORM_OSX_TRUE@xobjective_c = "-xobjective-c"
+@PLATFORM_OSX_TRUE@xobjective_cxx = "-xobjective-c++"
+@PLATFORM_OSX_TRUE@xnone = "-xnone"
+@PLATFORM_OSX_TRUE@framework_cocoa = -framework Cocoa
+@OS_WIN32_TRUE@mwindows = -mwindows
+@OS_WIN32_TRUE@WINSOCK_LIBS = -lws2_32
+@OS_WIN32_FALSE@libm = -lm
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la $(libm)
+libtinyscheme = tinyscheme/libtinyscheme.a $(libm)
+libftx = ftx/libftx.a
+@HAVE_WINDRES_TRUE@GIMPPLUGINRC = $(top_builddir)/build/windows/gimp-plug-ins.rc
+@HAVE_WINDRES_TRUE@script_fu_RC = script-fu.rc.o
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir) \
+ -DSTANDALONE=0 \
+ -DUSE_INTERFACE=1 \
+ -DUSE_STRLWR=0
+
+AM_CFLAGS = \
+ $(xobjective_c)
+
+AM_CXXFLAGS = \
+ $(xobjective_cxx)
+
+AM_LDFLAGS = \
+ $(mwindows) \
+ $(framework_cocoa) \
+ $(xnone)
+
+SUBDIRS = tinyscheme ftx scripts
+script_fu_SOURCES = \
+ script-fu-types.h \
+ script-fu-enums.h \
+ \
+ script-fu.c \
+ script-fu-console.c \
+ script-fu-console.h \
+ script-fu-eval.c \
+ script-fu-eval.h \
+ script-fu-interface.c \
+ script-fu-interface.h \
+ script-fu-text-console.h \
+ script-fu-text-console.c \
+ script-fu-intl.h \
+ script-fu-regex.c \
+ script-fu-regex.h \
+ script-fu-script.c \
+ script-fu-script.h \
+ script-fu-scripts.c \
+ script-fu-scripts.h \
+ script-fu-server.c \
+ script-fu-server.h \
+ script-fu-utils.c \
+ script-fu-utils.h \
+ scheme-wrapper.c \
+ scheme-wrapper.h
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimpmath) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpbase) \
+ $(libtinyscheme) \
+ $(libftx) \
+ $(GTK_LIBS) \
+ $(SOCKET_LIBS) \
+ $(WINSOCK_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(script_fu_RC)
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/windows/gimprc-plug-ins.rule $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/script-fu/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/script-fu/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/build/windows/gimprc-plug-ins.rule $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+script-fu$(EXEEXT): $(script_fu_OBJECTS) $(script_fu_DEPENDENCIES) $(EXTRA_script_fu_DEPENDENCIES)
+ @rm -f script-fu$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(script_fu_OBJECTS) $(script_fu_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheme-wrapper.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-console.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-eval.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-interface.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-regex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-script.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-scripts.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-server.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-text-console.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu-utils.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-fu.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libexecdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/scheme-wrapper.Po
+ -rm -f ./$(DEPDIR)/script-fu-console.Po
+ -rm -f ./$(DEPDIR)/script-fu-eval.Po
+ -rm -f ./$(DEPDIR)/script-fu-interface.Po
+ -rm -f ./$(DEPDIR)/script-fu-regex.Po
+ -rm -f ./$(DEPDIR)/script-fu-script.Po
+ -rm -f ./$(DEPDIR)/script-fu-scripts.Po
+ -rm -f ./$(DEPDIR)/script-fu-server.Po
+ -rm -f ./$(DEPDIR)/script-fu-text-console.Po
+ -rm -f ./$(DEPDIR)/script-fu-utils.Po
+ -rm -f ./$(DEPDIR)/script-fu.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libexecPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/scheme-wrapper.Po
+ -rm -f ./$(DEPDIR)/script-fu-console.Po
+ -rm -f ./$(DEPDIR)/script-fu-eval.Po
+ -rm -f ./$(DEPDIR)/script-fu-interface.Po
+ -rm -f ./$(DEPDIR)/script-fu-regex.Po
+ -rm -f ./$(DEPDIR)/script-fu-script.Po
+ -rm -f ./$(DEPDIR)/script-fu-scripts.Po
+ -rm -f ./$(DEPDIR)/script-fu-server.Po
+ -rm -f ./$(DEPDIR)/script-fu-text-console.Po
+ -rm -f ./$(DEPDIR)/script-fu-utils.Po
+ -rm -f ./$(DEPDIR)/script-fu.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-libexecPROGRAMS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-am clean clean-generic \
+ clean-libexecPROGRAMS clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libexecPROGRAMS install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-libexecPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# `windres` seems a very stupid tool and it breaks with double shlashes
+# in parameter paths. Strengthen the rule a little.
+@HAVE_WINDRES_TRUE@%.rc.o:
+@HAVE_WINDRES_TRUE@ $(WINDRES) --define ORIGINALFILENAME_STR="$*$(EXEEXT)" \
+@HAVE_WINDRES_TRUE@ --define INTERNALNAME_STR="$*" \
+@HAVE_WINDRES_TRUE@ --define TOP_SRCDIR="`echo $(top_srcdir) | sed 's*//*/*'`" \
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_srcdir)/app | sed 's%/\+%/%'`" \
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_builddir)/app | sed 's%/\+%/%'`"\
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_builddir) | sed 's%/\+%/%'`"\
+@HAVE_WINDRES_TRUE@ $(GIMPPLUGINRC) $@
+
+# Perform static analysis on all *.scm files and look for usage of
+# deprecated pdb procedures
+check-for-deprecated-procedures-in-script-fu:
+ @echo "Looking for deprecated procedures in *.scm files"
+ @scm_files=`find $(top_srcdir)/plug-ins/script-fu -name "*.scm"`; \
+ deprecated_procs=`$(top_builddir)/app/gimp-$(GIMP_APP_VERSION)$(EXEEXT) --dump-pdb-procedures-deprecated`; \
+ for scm_file in $$scm_files; do \
+ for proc in $$deprecated_procs; do \
+ if grep -Eq "^([^;]*[[:blank:](])?$$proc([[:blank:])]|$$)" $$scm_file; then \
+ echo "$${scm_file} uses deprecated procedure '$${proc}'"; \
+ fi \
+ done \
+ done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/script-fu/ftx/LICENSE b/plug-ins/script-fu/ftx/LICENSE
new file mode 100644
index 0000000..e820d87
--- /dev/null
+++ b/plug-ins/script-fu/ftx/LICENSE
@@ -0,0 +1,31 @@
+ LICENSE TERMS
+
+(c) 2002 Manuel Heras-Gilsanz (manuel@heras-gilsanz.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+Neither the name of Manuel Heras-Gilsanz nor the names of the
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/plug-ins/script-fu/ftx/Makefile.am b/plug-ins/script-fu/ftx/Makefile.am
new file mode 100644
index 0000000..46537bf
--- /dev/null
+++ b/plug-ins/script-fu/ftx/Makefile.am
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CFLAGS = \
+ -DUSE_INTERFACE=1 \
+ -I$(srcdir)/.. \
+ $(GLIB_CFLAGS)
+
+noinst_LIBRARIES = libftx.a
+
+libftx_a_SOURCES = ftx.c ftx.h
+
+EXTRA_DIST = \
+ LICENSE \
+ README \
+ ftx-functions.txt \
+ listhome.scm
diff --git a/plug-ins/script-fu/ftx/Makefile.in b/plug-ins/script-fu/ftx/Makefile.in
new file mode 100644
index 0000000..e71d6ae
--- /dev/null
+++ b/plug-ins/script-fu/ftx/Makefile.in
@@ -0,0 +1,912 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plug-ins/script-fu/ftx
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libftx_a_AR = $(AR) $(ARFLAGS)
+libftx_a_LIBADD =
+am_libftx_a_OBJECTS = ftx.$(OBJEXT)
+libftx_a_OBJECTS = $(am_libftx_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/ftx.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libftx_a_SOURCES)
+DIST_SOURCES = $(libftx_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CFLAGS = \
+ -DUSE_INTERFACE=1 \
+ -I$(srcdir)/.. \
+ $(GLIB_CFLAGS)
+
+noinst_LIBRARIES = libftx.a
+libftx_a_SOURCES = ftx.c ftx.h
+EXTRA_DIST = \
+ LICENSE \
+ README \
+ ftx-functions.txt \
+ listhome.scm
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/script-fu/ftx/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/script-fu/ftx/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libftx.a: $(libftx_a_OBJECTS) $(libftx_a_DEPENDENCIES) $(EXTRA_libftx_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libftx.a
+ $(AM_V_AR)$(libftx_a_AR) libftx.a $(libftx_a_OBJECTS) $(libftx_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libftx.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftx.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/ftx.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/ftx.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/script-fu/ftx/README b/plug-ins/script-fu/ftx/README
new file mode 100644
index 0000000..c20b215
--- /dev/null
+++ b/plug-ins/script-fu/ftx/README
@@ -0,0 +1,99 @@
+TinyScheme Extensions (TSX) 1.1 [September, 2002]
+(c) 2002 Manuel Heras-Gilsanz (manuel@heras-gilsanz.com)
+
+This software is subject to the license terms contained in the
+LICENSE file.
+
+Changelog:
+1.1 (Sept. 2002) Updated to tinyscheme 1.31
+1.0 (April 2002) First released version
+
+
+WHAT IS TSX?
+
+TinyScheme Extensions is a set of dynamic libraries incorporating
+additional funcionality to TinyScheme, a lightweight
+implementation of the Scheme programming language. TinyScheme
+(http://tinyscheme.sourceforge.net) is maintained by D. Souflis
+(dsouflis@acm.org), and is based on MiniSCHEME version 0.85k4.
+
+Scheme is a very nice and powerful programming language, but the
+basic language is very minimalistic in terms of library functions;
+only basic file input / output functionality is specified.
+Different implementations of the language (MIT Scheme, GUILE,
+Bigloo...) provide their own extension libraries. TSX attempts to
+provide commonly needed functions at a small cost in terms of
+additional program footprint. The library is modularized, so that
+it is possible (and easy!) to select desired functionality via
+#defines in tsx.h.
+
+
+INSTALLATION
+
+TSX has been tested on GNU/Linux 2.4.2 with gcc 2.96 and
+libc-2.2.2, with TinyScheme 1.31.
+
+To install, copy the distribution file to the directory
+where TinyScheme is installed (and where scheme.h lies),
+and run make. If building succeeds, a file called tsx.so
+should be created. This file can be loaded as a TinyScheme
+extension with
+
+ (load-extension "tsx-1.0/tsx")
+
+After loading TSX, you can make use of its functions.
+To reduce footprint, you can choose the functionality which
+will be included. To do so, have a look at tsx.h and
+comment the #defines for unneeded modules.
+
+If you get compiler errors, make sure you have enabled
+dynamic modules in your tinyscheme runtime (define USE_DL
+somewhere near the top in scheme.h).
+
+
+SAMPLE APPLICATIONS
+
+Three sample applications are distributed with TSX 1.0.
+The code is not particularly elegant, nor written in proper
+functional style, but is provided for illustration of the
+implemented calls.
+
+-smtp.scm
+ Sends an email to the user getting the username from
+ the USER shell variable, connecting to the SMTP port
+ on the local machine.
+
+-listhome.scm
+ Provides a list of all the files on the user's home
+ directory (obtained with the HOME environment variable).
+
+-srepl.scm
+ Provides a socket-based read-eval-print-loop. It listens
+ for connections on the 9000 port of the local machines,
+ and executes the commands received. To test it, run
+
+ telnet localhost 9000
+
+ after starting the sample application, and type Scheme
+ expressions. You will get the evaluations. To exit the
+ session, type "quit" and TinyScheme will exit, closing
+ the socket. The output of some functions will not
+ be the same as you would obtain on TinyScheme's
+ "command line", because standard output is not
+ redirected to the socket, but most commands work ok.
+
+You should copy these applications to the directory where
+TinyScheme is installed (i.e., where the "scheme" binary
+file resides), and can be run with:
+
+ ./scheme listhome.scm
+ ./scheme smtp.scm
+ ./scheme srepl.scm
+
+
+TSX FUNCTIONS
+
+The extension functions implemented by TinyScheme Extensions are
+documented in the file "tsx-functions.txt".
+
+END
diff --git a/plug-ins/script-fu/ftx/ftx-functions.txt b/plug-ins/script-fu/ftx/ftx-functions.txt
new file mode 100644
index 0000000..5365bc5
--- /dev/null
+++ b/plug-ins/script-fu/ftx/ftx-functions.txt
@@ -0,0 +1,119 @@
+File and Time Extensions for TinyScheme (FTX) 1.0 [August, 2004]
+
+Based on the TinyScheme Extensions (TSX) 1.1 [September, 2002]
+(c) 2002 Manuel Heras-Gilsanz (manuel@heras-gilsanz.com)
+
+This software is subject to the license terms contained in the
+LICENSE file.
+
+
+TSX FUNCTIONS
+
+TSX incorporates the following functions:
+
+*File system (included if HAVE_FILESYSTEM is defined in tsx.h)
+
+Scheme already defines functions to read and write files. These
+functions allow access to the filesystem to check if a certain
+file exists, to get its size, etc.
+
+In addition to these functions, a string constant DIR-SEPARATOR
+has been defined. It should be used in scripts which build file
+names that include one or more directories to keep the scripts
+portable to different operating systems.
+
+(file-exists? filename)
+ filename: string
+
+ This function returns #t if the indicated file exists, and
+ #f if it does not exist or if it is not accessible to the
+ requesting user. Accessibility is based on the real user
+ and group ID rather than the effective user ID and group ID.
+
+(file-type filename)
+ filename: string
+
+ This function returns a value based on the file type. It
+ returns FILE_TYPE_FILE (1) for regular files, FILE_TYPE_DIR
+ (2) for directories, and FILE_TYPE_LINK (3) for symbolic
+ links. The value FILE_TYPE_OTHER (0) is returned if the file
+ is of some other type, does not exist, or if the user does
+ not have sufficient privileges to allow the file type to be
+ determined.
+
+(file-size filename)
+ filename: string
+
+ This function returns the size (in bytes) of the
+ indicated file, or #f if the file does not exists or
+ is not accessible to the requesting user.
+
+(file-delete filename)
+ filename: string
+
+ Removes the specified file. It returns #t if the operation
+ succeeds, or #f otherwise (e.g., because the file is
+ read-only, or because the file does not exist).
+
+(dir-open-stream path)
+ path: string
+
+ Opens a "directory stream" on the provided directory path.
+ This stream will provide all the files within the directory,
+ using the function read-dir-entry. The stream should be closed
+ at the end with dir-close-stream.
+
+(dir-read-entry dirstream)
+ dirstream: directory stream, obtained with dir-open-stream.
+
+ It returns the name of the following directory entry, or eof
+ if all the entries were provided. Check the return value with
+ with eof-object?.
+
+(dir-rewind dirstream)
+ dirstream: directory stream, obtained with dir-open-stream.
+
+ Resets the given directory stream. The next call to dir-read-entry
+ will return the first entry again. It returns #t if the operation
+ succeeds, or #f otherwise (ie. dirstream not valid)..
+
+(dir-close-stream dirstream)
+ dirstream: directory stream, obtained with dir-open-stream.
+
+ Close directory stream. No further calls to read-dir-entry should
+ be performed.
+
+(dir-make dirname . mode)
+ dirname: string
+ mode: integer representing permissions
+
+ Create the directory specified, setting the directory permissions based
+ upon the optional mode argument (taking into account the current
+ umask). If no mode is specified then use the default (umask)
+ permissions. Returns #t if the operation succeeds, otherwise #f.
+ Possible reasons for failure are that the directory already exists,
+ the user is not authorized to create it, or the mode is incorrectly
+ specified).
+
+*Time (available if HAVE_TIME is defined in tsx.h)
+
+(time)
+ Returns the current local time, as a list of integer
+ containing:
+ (year month day-of-month hour min sec millisec)
+ The year is expressed as an offset from 1900.
+
+(gettimeofday)
+ Returns a list containing the number of seconds from
+ the beginning of the day, and microseconds within the
+ current second.
+
+(usleep microsec)
+ microsec: integer
+
+ Suspends execution of the calling thread during the
+ specified number of microseconds.
+
+
+END
+
diff --git a/plug-ins/script-fu/ftx/ftx.c b/plug-ins/script-fu/ftx/ftx.c
new file mode 100644
index 0000000..f9de1bf
--- /dev/null
+++ b/plug-ins/script-fu/ftx/ftx.c
@@ -0,0 +1,415 @@
+/* TinyScheme Extensions
+ * (c) 2002 Visual Tools, S.A.
+ * Manuel Heras-Gilsanz (manuel@heras-gilsanz.com)
+ *
+ * This software is subject to the terms stated in the
+ * LICENSE file.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+
+#include <glib.h>
+
+#include "tinyscheme/scheme-private.h"
+
+#undef cons
+
+typedef enum
+{
+ FILE_TYPE_UNKNOWN = 0, FILE_TYPE_FILE, FILE_TYPE_DIR, FILE_TYPE_LINK
+} FileType;
+
+struct
+named_constant {
+ const char *name;
+ FileType value;
+};
+
+struct named_constant
+file_type_constants[] = {
+ { "FILE-TYPE-UNKNOWN", FILE_TYPE_UNKNOWN },
+ { "FILE-TYPE-FILE", FILE_TYPE_FILE },
+ { "FILE-TYPE-DIR", FILE_TYPE_DIR },
+ { "FILE-TYPE-LINK", FILE_TYPE_LINK },
+ { NULL, 0 }
+};
+
+pointer foreign_fileexists(scheme *sc, pointer args);
+pointer foreign_filetype(scheme *sc, pointer args);
+pointer foreign_filesize(scheme *sc, pointer args);
+pointer foreign_filedelete(scheme *sc, pointer args);
+pointer foreign_diropenstream(scheme *sc, pointer args);
+pointer foreign_dirreadentry(scheme *sc, pointer args);
+pointer foreign_dirrewind(scheme *sc, pointer args);
+pointer foreign_dirclosestream(scheme *sc, pointer args);
+pointer foreign_mkdir(scheme *sc, pointer args);
+
+pointer foreign_getenv(scheme *sc, pointer args);
+pointer foreign_time(scheme *sc, pointer args);
+pointer foreign_gettimeofday(scheme *sc, pointer args);
+pointer foreign_usleep(scheme *sc, pointer args);
+void init_ftx (scheme *sc);
+
+
+pointer foreign_fileexists(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ char *filename;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+
+ filename = sc->vptr->string_value(first_arg);
+ filename = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
+ if (g_file_test(filename, G_FILE_TEST_EXISTS))
+ return sc->T;
+
+ return sc->F;
+}
+
+pointer foreign_filetype(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ char *filename;
+ int retcode;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+
+ filename = sc->vptr->string_value(first_arg);
+ filename = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
+
+ if (g_file_test(filename, G_FILE_TEST_IS_SYMLINK))
+ retcode = FILE_TYPE_LINK;
+ else if (g_file_test(filename, G_FILE_TEST_IS_REGULAR))
+ retcode = FILE_TYPE_FILE;
+ else if (g_file_test(filename, G_FILE_TEST_IS_DIR))
+ retcode = FILE_TYPE_DIR;
+ else
+ retcode = FILE_TYPE_UNKNOWN;
+
+ return sc->vptr->mk_integer(sc, retcode);
+}
+
+pointer foreign_filesize(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ pointer ret;
+ struct stat buf;
+ char * filename;
+ int retcode;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+
+ filename = sc->vptr->string_value(first_arg);
+ filename = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
+ retcode = stat(filename, &buf);
+ if (retcode == 0)
+ ret = sc->vptr->mk_integer(sc,buf.st_size);
+ else
+ ret = sc->F;
+ return ret;
+}
+
+pointer foreign_filedelete(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ pointer ret;
+ char * filename;
+ int retcode;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg)) {
+ return sc->F;
+ }
+
+ filename = sc->vptr->string_value(first_arg);
+ filename = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
+ retcode = unlink(filename);
+ if (retcode == 0)
+ ret = sc->T;
+ else
+ ret = sc->F;
+ return ret;
+}
+
+pointer foreign_diropenstream(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ char *dirpath;
+ GDir *dir;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+
+ dirpath = sc->vptr->string_value(first_arg);
+ dirpath = g_filename_from_utf8 (dirpath, -1, NULL, NULL, NULL);
+
+ dir = g_dir_open(dirpath, 0, NULL);
+ if (dir == NULL)
+ return sc->F;
+
+ /* Stuffing a pointer in a long may not always be portable ~~~~~ */
+ return (sc->vptr->mk_integer(sc, (long) dir));
+}
+
+pointer foreign_dirreadentry(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ GDir *dir;
+ gchar *entry;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_integer(first_arg))
+ return sc->F;
+
+ dir = (GDir *) sc->vptr->ivalue(first_arg);
+ if (dir == NULL)
+ return sc->F;
+
+ entry = (gchar *)g_dir_read_name(dir);
+ if (entry == NULL)
+ return sc->EOF_OBJ;
+
+ entry = g_filename_to_utf8 (entry, -1, NULL, NULL, NULL);
+ return (sc->vptr->mk_string(sc, entry));
+}
+
+pointer foreign_dirrewind(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ GDir *dir;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_integer(first_arg))
+ return sc->F;
+
+ dir = (GDir *) sc->vptr->ivalue(first_arg);
+ if (dir == NULL)
+ return sc->F;
+
+ g_dir_rewind(dir);
+ return sc->T;
+}
+
+pointer foreign_dirclosestream(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ GDir *dir;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_integer(first_arg))
+ return sc->F;
+
+ dir = (GDir *) sc->vptr->ivalue(first_arg);
+ if (dir == NULL)
+ return sc->F;
+
+ g_dir_close(dir);
+ return sc->T;
+}
+
+pointer foreign_mkdir(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ pointer rest;
+ pointer second_arg;
+ char *dirname;
+ mode_t mode;
+ int retcode;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+ dirname = sc->vptr->string_value(first_arg);
+ dirname = g_filename_from_utf8 (dirname, -1, NULL, NULL, NULL);
+
+ rest = sc->vptr->pair_cdr(args);
+ if (sc->vptr->is_pair(rest)) /* optional mode argument */
+ {
+ second_arg = sc->vptr->pair_car(rest);
+ if (!sc->vptr->is_integer(second_arg))
+ return sc->F;
+ mode = sc->vptr->ivalue(second_arg);
+ }
+ else
+ mode = 0777;
+
+ retcode = g_mkdir(dirname, (mode_t)mode);
+ if (retcode == 0)
+ return sc->T;
+ else
+ return sc->F;
+}
+
+pointer foreign_getenv(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ pointer ret;
+ char *varname;
+ const char *value;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+
+ if (!sc->vptr->is_string(first_arg))
+ return sc->F;
+
+ varname = sc->vptr->string_value(first_arg);
+ value = g_getenv(varname);
+ if (value == NULL)
+ ret = sc->F;
+ else
+ ret = sc->vptr->mk_string(sc,value);
+
+ return ret;
+}
+
+pointer foreign_time(scheme *sc, pointer args)
+{
+ time_t now;
+ struct tm *now_tm;
+ pointer ret;
+
+ if (args != sc->NIL)
+ return sc->F;
+
+ time(&now);
+ now_tm = localtime(&now);
+
+ ret = sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_year),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_mon),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_mday),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_hour),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_min),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) now_tm->tm_sec),sc->NIL))))));
+
+ return ret;
+}
+
+pointer foreign_gettimeofday(scheme *sc, pointer args)
+{
+ pointer ret;
+ gint64 time;
+
+ time = g_get_real_time ();
+
+ ret = sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) time / G_USEC_PER_SEC),
+ sc->vptr->cons(sc, sc->vptr->mk_integer(sc,(long) time % G_USEC_PER_SEC),
+ sc->NIL));
+
+ return ret;
+}
+
+pointer foreign_usleep(scheme *sc, pointer args)
+{
+ pointer first_arg;
+ long usec;
+
+ if (args == sc->NIL)
+ return sc->F;
+
+ first_arg = sc->vptr->pair_car(args);
+ if (!sc->vptr->is_integer(first_arg))
+ return sc->F;
+
+ usec = sc->vptr->ivalue(first_arg);
+ g_usleep(usec);
+
+ return sc->T;
+}
+
+/* This function gets called when TinyScheme is loading the extension */
+void init_ftx (scheme *sc)
+{
+ int i;
+
+ sc->vptr->scheme_define(sc,sc->global_env,
+ sc->vptr->mk_symbol(sc,"getenv"),
+ sc->vptr->mk_foreign_func(sc, foreign_getenv));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"time"),
+ sc->vptr->mk_foreign_func(sc, foreign_time));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"gettimeofday"),
+ sc->vptr->mk_foreign_func(sc, foreign_gettimeofday));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"usleep"),
+ sc->vptr->mk_foreign_func(sc, foreign_usleep));
+
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"file-exists?"),
+ sc->vptr->mk_foreign_func(sc, foreign_fileexists));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"file-type"),
+ sc->vptr->mk_foreign_func(sc, foreign_filetype));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"file-size"),
+ sc->vptr->mk_foreign_func(sc, foreign_filesize));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"file-delete"),
+ sc->vptr->mk_foreign_func(sc, foreign_filedelete));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"dir-open-stream"),
+ sc->vptr->mk_foreign_func(sc, foreign_diropenstream));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"dir-read-entry"),
+ sc->vptr->mk_foreign_func(sc, foreign_dirreadentry));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"dir-rewind"),
+ sc->vptr->mk_foreign_func(sc, foreign_dirrewind));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"dir-close-stream"),
+ sc->vptr->mk_foreign_func(sc, foreign_dirclosestream));
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc,"dir-make"),
+ sc->vptr->mk_foreign_func(sc, foreign_mkdir));
+
+ for (i = 0; file_type_constants[i].name != NULL; ++i)
+ {
+ sc->vptr->scheme_define(sc, sc->global_env,
+ sc->vptr->mk_symbol(sc, file_type_constants[i].name),
+ sc->vptr->mk_integer(sc, file_type_constants[i].value));
+ }
+}
diff --git a/plug-ins/script-fu/ftx/ftx.h b/plug-ins/script-fu/ftx/ftx.h
new file mode 100644
index 0000000..f40c30d
--- /dev/null
+++ b/plug-ins/script-fu/ftx/ftx.h
@@ -0,0 +1,2 @@
+/* This function gets called when TinyScheme is initializing the extension */
+void init_ftx (scheme *sc);
diff --git a/plug-ins/script-fu/ftx/listhome.scm b/plug-ins/script-fu/ftx/listhome.scm
new file mode 100644
index 0000000..1fa8d14
--- /dev/null
+++ b/plug-ins/script-fu/ftx/listhome.scm
@@ -0,0 +1,58 @@
+; listhome.scm
+; Sample usage of TinyScheme Extension
+; This simple program lists the directory entries on the
+; user's home directory.
+
+; It uses the following TinyScheme Extension functions:
+; getenv
+; Used to get HOME environment variable.
+; open-dir-stream
+; Used to open directory stream.
+; read-dir-entry
+; Used to read directory entries.
+; close-dir-entry
+; Used at the end, to close directory stream when done.
+
+; check that extensions are enabled
+(if (not (defined? 'load-extension))
+ (begin
+ (display "TinyScheme has extensions disabled. Enable them!!")
+ (newline)
+ (quit)))
+
+; load TinyScheme extension
+(load-extension "tsx-1.1/tsx")
+
+; check that the necessary functions are available (the user
+; might have removed some functionality...)
+(if (or
+ (not (defined? 'getenv))
+ (not (defined? 'dir-open-stream))
+ (not (defined? 'dir-read-entry))
+ (not (defined? 'dir-close-stream)))
+ (begin
+ (display "Some necessary functions are not available. Exiting!")
+ (newline)
+ (quit)))
+
+; get user's home dir from HOME environment var
+(define homedir (getenv "HOME"))
+(display "Listing contents of ") (display homedir) (newline)
+
+; create directory stream to read dir entries
+(define dirstream (dir-open-stream homedir))
+(if (not dirstream)
+ (begin
+ (display "Unable to open home directory!! Check value of HOME environment var.")
+ (quit)))
+
+(let listentry ((entry (dir-read-entry dirstream)))
+ (if (eof-object? entry)
+ #t
+ (begin
+ (display entry)
+ (newline)
+ (listentry (dir-read-entry dirstream)))))
+
+(dir-close-stream dirstream)
+
diff --git a/plug-ins/script-fu/scheme-wrapper.c b/plug-ins/script-fu/scheme-wrapper.c
new file mode 100644
index 0000000..69e22c0
--- /dev/null
+++ b/plug-ins/script-fu/scheme-wrapper.c
@@ -0,0 +1,1671 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if 0
+#define DEBUG_MARSHALL 0 /* No need to define this until you need it */
+#define DEBUG_SCRIPTS 0
+#endif
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "libgimp/gimp.h"
+
+#include "tinyscheme/scheme-private.h"
+#if USE_DL
+#include "tinyscheme/dynload.h"
+#endif
+#include "ftx/ftx.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-console.h"
+#include "script-fu-interface.h"
+#include "script-fu-regex.h"
+#include "script-fu-scripts.h"
+#include "script-fu-server.h"
+
+#include "scheme-wrapper.h"
+
+
+#undef cons
+
+static void ts_init_constants (scheme *sc);
+static void ts_init_enum (scheme *sc,
+ GType enum_type);
+static void ts_init_procedures (scheme *sc,
+ gboolean register_scipts);
+static void convert_string (gchar *str);
+static pointer script_fu_marshal_procedure_call (scheme *sc,
+ pointer a,
+ gboolean permissive);
+static pointer script_fu_marshal_procedure_call_strict (scheme *sc,
+ pointer a);
+static pointer script_fu_marshal_procedure_call_permissive (scheme *sc,
+ pointer a);
+static void script_fu_marshal_destroy_args (GimpParam *params,
+ gint n_params);
+
+static pointer script_fu_register_call (scheme *sc,
+ pointer a);
+static pointer script_fu_menu_register_call (scheme *sc,
+ pointer a);
+static pointer script_fu_quit_call (scheme *sc,
+ pointer a);
+static pointer script_fu_nil_call (scheme *sc,
+ pointer a);
+
+static gboolean ts_load_file (const gchar *dirname,
+ const gchar *basename);
+
+typedef struct
+{
+ const gchar *name;
+ gint value;
+} NamedConstant;
+
+static const NamedConstant script_constants[] =
+{
+ /* Useful values from libgimpbase/gimplimits.h */
+ { "MIN-IMAGE-SIZE", GIMP_MIN_IMAGE_SIZE },
+ { "MAX-IMAGE-SIZE", GIMP_MAX_IMAGE_SIZE },
+ { "MIN-RESOLUTION", GIMP_MIN_RESOLUTION },
+ { "MAX-RESOLUTION", GIMP_MAX_RESOLUTION },
+
+ /* Useful misc stuff */
+ { "TRUE", TRUE },
+ { "FALSE", FALSE },
+
+ /* Builtin units */
+ { "UNIT-PIXEL", GIMP_UNIT_PIXEL },
+ { "UNIT-INCH", GIMP_UNIT_INCH },
+ { "UNIT-MM", GIMP_UNIT_MM },
+ { "UNIT-POINT", GIMP_UNIT_POINT },
+ { "UNIT-PICA", GIMP_UNIT_PICA },
+
+ /* Script-Fu types */
+ { "SF-IMAGE", SF_IMAGE },
+ { "SF-DRAWABLE", SF_DRAWABLE },
+ { "SF-LAYER", SF_LAYER },
+ { "SF-CHANNEL", SF_CHANNEL },
+ { "SF-VECTORS", SF_VECTORS },
+ { "SF-COLOR", SF_COLOR },
+ { "SF-TOGGLE", SF_TOGGLE },
+ { "SF-VALUE", SF_VALUE },
+ { "SF-STRING", SF_STRING },
+ { "SF-FILENAME", SF_FILENAME },
+ { "SF-DIRNAME", SF_DIRNAME },
+ { "SF-ADJUSTMENT", SF_ADJUSTMENT },
+ { "SF-FONT", SF_FONT },
+ { "SF-PATTERN", SF_PATTERN },
+ { "SF-BRUSH", SF_BRUSH },
+ { "SF-GRADIENT", SF_GRADIENT },
+ { "SF-OPTION", SF_OPTION },
+ { "SF-PALETTE", SF_PALETTE },
+ { "SF-TEXT", SF_TEXT },
+ { "SF-ENUM", SF_ENUM },
+ { "SF-DISPLAY", SF_DISPLAY },
+
+ /* For SF-ADJUSTMENT */
+ { "SF-SLIDER", SF_SLIDER },
+ { "SF-SPINNER", SF_SPINNER },
+
+ { NULL, 0 }
+};
+
+
+static scheme sc;
+
+
+void
+tinyscheme_init (GList *path,
+ gboolean register_scripts)
+{
+ /* init the interpreter */
+ if (! scheme_init (&sc))
+ {
+ g_message ("Could not initialize TinyScheme!");
+ return;
+ }
+
+ scheme_set_input_port_file (&sc, stdin);
+ scheme_set_output_port_file (&sc, stdout);
+ ts_register_output_func (ts_stdout_output_func, NULL);
+
+ /* Initialize the TinyScheme extensions */
+ init_ftx (&sc);
+ script_fu_regex_init (&sc);
+
+ /* register in the interpreter the gimp functions and types. */
+ ts_init_constants (&sc);
+ ts_init_procedures (&sc, register_scripts);
+
+ if (path)
+ {
+ GList *list;
+
+ for (list = path; list; list = g_list_next (list))
+ {
+ gchar *dir = g_file_get_path (list->data);
+
+ if (ts_load_file (dir, "script-fu.init"))
+ {
+ /* To improve compatibility with older Script-Fu scripts,
+ * load script-fu-compat.init from the same directory.
+ */
+ ts_load_file (dir, "script-fu-compat.init");
+
+ /* To improve compatibility with older GIMP version,
+ * load plug-in-compat.init from the same directory.
+ */
+ ts_load_file (dir, "plug-in-compat.init");
+
+ g_free (dir);
+
+ break;
+ }
+
+ g_free (dir);
+ }
+
+ if (list == NULL)
+ g_printerr ("Unable to read initialization file script-fu.init\n");
+ }
+}
+
+/* Create an SF-RUN-MODE constant for use in scripts.
+ * It is set to the run mode state determined by GIMP.
+ */
+void
+ts_set_run_mode (GimpRunMode run_mode)
+{
+ pointer symbol;
+
+ symbol = sc.vptr->mk_symbol (&sc, "SF-RUN-MODE");
+ sc.vptr->scheme_define (&sc, sc.global_env, symbol,
+ sc.vptr->mk_integer (&sc, run_mode));
+ sc.vptr->setimmutable (symbol);
+}
+
+void
+ts_set_print_flag (gint print_flag)
+{
+ sc.print_output = print_flag;
+}
+
+void
+ts_print_welcome (void)
+{
+ ts_output_string (TS_OUTPUT_NORMAL,
+ "Welcome to TinyScheme, Version 1.40\n", -1);
+ ts_output_string (TS_OUTPUT_NORMAL,
+ "Copyright (c) Dimitrios Souflis\n", -1);
+}
+
+void
+ts_interpret_stdin (void)
+{
+ scheme_load_file (&sc, stdin);
+}
+
+gint
+ts_interpret_string (const gchar *expr)
+{
+#if DEBUG_SCRIPTS
+ sc.print_output = 1;
+ sc.tracing = 1;
+#endif
+
+ sc.vptr->load_string (&sc, (char *) expr);
+
+ return sc.retcode;
+}
+
+const gchar *
+ts_get_success_msg (void)
+{
+ if (sc.vptr->is_string (sc.value))
+ return sc.vptr->string_value (sc.value);
+
+ return "Success";
+}
+
+void
+ts_stdout_output_func (TsOutputType type,
+ const char *string,
+ int len,
+ gpointer user_data)
+{
+ if (len < 0)
+ len = strlen (string);
+ fprintf (stdout, "%.*s", len, string);
+ fflush (stdout);
+}
+
+void
+ts_gstring_output_func (TsOutputType type,
+ const char *string,
+ int len,
+ gpointer user_data)
+{
+ GString *gstr = (GString *) user_data;
+
+ g_string_append_len (gstr, string, len);
+}
+
+
+/* private functions */
+
+/*
+ * Below can be found the functions responsible for registering the
+ * gimp functions and types against the scheme interpreter.
+ */
+static void
+ts_init_constants (scheme *sc)
+{
+ const gchar **enum_type_names;
+ gint n_enum_type_names;
+ gint i;
+ pointer symbol;
+ GQuark quark;
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-data-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_data_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-plug-in-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_plug_in_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-locale-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_locale_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-sysconf-directory");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_sysconf_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ enum_type_names = gimp_enums_get_type_names (&n_enum_type_names);
+ quark = g_quark_from_static_string ("gimp-compat-enum");
+
+ for (i = 0; i < n_enum_type_names; i++)
+ {
+ const gchar *enum_name = enum_type_names[i];
+ GType enum_type = g_type_from_name (enum_name);
+
+ ts_init_enum (sc, enum_type);
+
+ enum_type = (GType) g_type_get_qdata (enum_type, quark);
+
+ if (enum_type)
+ ts_init_enum (sc, enum_type);
+ }
+
+ /* Constants used in the register block of scripts */
+ for (i = 0; script_constants[i].name != NULL; ++i)
+ {
+ symbol = sc->vptr->mk_symbol (sc, script_constants[i].name);
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_integer (sc,
+ script_constants[i].value));
+ sc->vptr->setimmutable (symbol);
+ }
+
+ /* Define string constant for use in building paths to files/directories */
+ symbol = sc->vptr->mk_symbol (sc, "DIR-SEPARATOR");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, G_DIR_SEPARATOR_S));
+ sc->vptr->setimmutable (symbol);
+
+ /* Define string constant for use in building search paths */
+ symbol = sc->vptr->mk_symbol (sc, "SEARCHPATH-SEPARATOR");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, G_SEARCHPATH_SEPARATOR_S));
+ sc->vptr->setimmutable (symbol);
+
+ /* These constants are deprecated and will be removed at a later date. */
+ symbol = sc->vptr->mk_symbol (sc, "gimp-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-data-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_data_directory ()));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "gimp-plugin-dir");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_string (sc, gimp_plug_in_directory ()));
+ sc->vptr->setimmutable (symbol);
+}
+
+static void
+ts_init_enum (scheme *sc,
+ GType enum_type)
+{
+ GEnumClass *enum_class = g_type_class_ref (enum_type);
+ GEnumValue *value;
+
+ for (value = enum_class->values; value->value_name; value++)
+ {
+ if (g_str_has_prefix (value->value_name, "GIMP_"))
+ {
+ gchar *scheme_name;
+ pointer symbol;
+
+ scheme_name = g_strdup (value->value_name + strlen ("GIMP_"));
+ convert_string (scheme_name);
+
+ symbol = sc->vptr->mk_symbol (sc, scheme_name);
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_integer (sc, value->value));
+ sc->vptr->setimmutable (symbol);
+
+ g_free (scheme_name);
+ }
+ }
+
+ g_type_class_unref (enum_class);
+}
+
+static void
+ts_init_procedures (scheme *sc,
+ gboolean register_scripts)
+{
+ gchar **proc_list;
+ gint num_procs;
+ gint i;
+ pointer symbol;
+
+#if USE_DL
+ symbol = sc->vptr->mk_symbol (sc,"load-extension");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc, scm_load_ext));
+ sc->vptr->setimmutable (symbol);
+#endif
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-register");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ register_scripts ?
+ script_fu_register_call :
+ script_fu_nil_call));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-menu-register");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ register_scripts ?
+ script_fu_menu_register_call :
+ script_fu_nil_call));
+ sc->vptr->setimmutable (symbol);
+
+ symbol = sc->vptr->mk_symbol (sc, "script-fu-quit");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc, script_fu_quit_call));
+ sc->vptr->setimmutable (symbol);
+
+ /* register the database execution procedure */
+ symbol = sc->vptr->mk_symbol (sc, "gimp-proc-db-call");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ script_fu_marshal_procedure_call_strict));
+ sc->vptr->setimmutable (symbol);
+
+ /* register the internal database execution procedure; see comment below */
+ symbol = sc->vptr->mk_symbol (sc, "-gimp-proc-db-call");
+ sc->vptr->scheme_define (sc, sc->global_env, symbol,
+ sc->vptr->mk_foreign_func (sc,
+ script_fu_marshal_procedure_call_permissive));
+ sc->vptr->setimmutable (symbol);
+
+ gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*",
+ &num_procs, &proc_list);
+
+ /* Register each procedure as a scheme func */
+ for (i = 0; i < num_procs; i++)
+ {
+ gchar *buff;
+
+ /* Build a define that will call the foreign function.
+ * The Scheme statement was suggested by Simon Budig.
+ *
+ * We call the procedure through -gimp-proc-db-call, which is a more
+ * permissive version of gimp-proc-db-call, that accepts (and ignores)
+ * any number of arguments for nullary procedures, for backward
+ * compatibility.
+ */
+ buff = g_strdup_printf (" (define (%s . args)"
+ " (apply -gimp-proc-db-call \"%s\" args))",
+ proc_list[i], proc_list[i]);
+
+ /* Execute the 'define' */
+ sc->vptr->load_string (sc, buff);
+
+ g_free (buff);
+ }
+
+ g_strfreev (proc_list);
+}
+
+static gboolean
+ts_load_file (const gchar *dirname,
+ const gchar *basename)
+{
+ gchar *filename;
+ FILE *fin;
+
+ filename = g_build_filename (dirname, basename, NULL);
+
+ fin = g_fopen (filename, "rb");
+
+ g_free (filename);
+
+ if (fin)
+ {
+ scheme_load_file (&sc, fin);
+ fclose (fin);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+convert_string (gchar *str)
+{
+ while (*str)
+ {
+ if (*str == '_') *str = '-';
+ str++;
+ }
+}
+
+/* This is called by the Scheme interpreter to allow calls to GIMP functions */
+static pointer
+script_fu_marshal_procedure_call (scheme *sc,
+ pointer a,
+ gboolean permissive)
+{
+ GimpParam *args;
+ GimpParam *values = NULL;
+ gint nvalues;
+ gchar *proc_name;
+ gchar *proc_blurb;
+ gchar *proc_help;
+ gchar *proc_author;
+ gchar *proc_copyright;
+ gchar *proc_date;
+ GimpPDBProcType proc_type;
+ gint nparams;
+ gint nreturn_vals;
+ GimpParamDef *params;
+ GimpParamDef *return_vals;
+ gchar error_str[1024];
+ gint i;
+ gint success = TRUE;
+ pointer return_val = sc->NIL;
+
+#if DEBUG_MARSHALL
+/* These three #defines are from Tinyscheme (tinyscheme/scheme.c) */
+#define T_MASKTYPE 31
+#define typeflag(p) ((p)->_flag)
+#define type(p) (typeflag(p)&T_MASKTYPE)
+
+ static const char *ts_types[] =
+ {
+ "T_NONE",
+ "T_STRING", "T_NUMBER", "T_SYMBOL", "T_PROC",
+ "T_PAIR", "T_CLOSURE", "T_CONTINUATION", "T_FOREIGN",
+ "T_CHARACTER", "T_PORT", "T_VECTOR", "T_MACRO",
+ "T_PROMISE", "T_ENVIRONMENT","T_ARRAY"
+ };
+
+ g_printerr ("\nIn %s()\n", G_STRFUNC);
+#endif
+
+ /* Make sure there are arguments */
+ if (a == sc->NIL)
+ return foreign_error (sc,
+ "Procedure argument marshaller was called with no arguments. "
+ "The procedure to be executed and the arguments it requires "
+ "(possibly none) must be specified.", 0);
+
+ /* The PDB procedure name is the argument or first argument of the list */
+ if (sc->vptr->is_pair (a))
+ proc_name = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a)));
+ else
+ proc_name = g_strdup (sc->vptr->string_value (a));
+
+#ifdef DEBUG_MARSHALL
+ g_printerr (" proc name: %s\n", proc_name);
+ g_printerr (" parms rcvd: %d\n", sc->vptr->list_length (sc, a)-1);
+#endif
+
+ /* report the current command */
+ script_fu_interface_report_cc (proc_name);
+
+ /* Attempt to fetch the procedure from the database */
+ if (! gimp_procedural_db_proc_info (proc_name,
+ &proc_blurb,
+ &proc_help,
+ &proc_author,
+ &proc_copyright,
+ &proc_date,
+ &proc_type,
+ &nparams, &nreturn_vals,
+ &params, &return_vals))
+ {
+#ifdef DEBUG_MARSHALL
+ g_printerr (" Invalid procedure name\n");
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid procedure name %s specified", proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Free the name and the description which are of no use here. */
+ for (i = 0; i < nparams; i++)
+ {
+ g_free (params[i].name);
+ g_free (params[i].description);
+ }
+ for (i = 0; i < nreturn_vals; i++)
+ {
+ g_free (return_vals[i].name);
+ g_free (return_vals[i].description);
+ }
+
+ /* Check the supplied number of arguments */
+ if ((nparams > 0 || ! permissive) &&
+ (sc->vptr->list_length (sc, a) - 1) != nparams)
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Invalid number of arguments (expected %d but received %d)",
+ nparams, (sc->vptr->list_length (sc, a) - 1));
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid number of arguments for %s (expected %d but received %d)",
+ proc_name, nparams, (sc->vptr->list_length (sc, a) - 1));
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Marshall the supplied arguments */
+ if (nparams)
+ args = g_new (GimpParam, nparams);
+ else
+ args = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ gint32 n_elements;
+ pointer vector;
+ gint j;
+
+ a = sc->vptr->pair_cdr (a);
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *type_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE,
+ params[i].type,
+ &type_name, NULL, NULL, NULL);
+
+ g_printerr (" param %d - expecting type %s (%d)\n",
+ i + 1, type_name, params[i].type);
+ g_printerr (" passed arg is type %s (%d)\n",
+ ts_types[ type(sc->vptr->pair_car (a)) ],
+ type(sc->vptr->pair_car (a)));
+ }
+#endif
+
+ args[i].type = params[i].type;
+
+ switch (params[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int32 = sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int32 arg is '%d'\n", args[i].data.d_int32);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT16:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int16 = (gint16) sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int16 arg is '%d'\n", args[i].data.d_int16);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT8:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_int8 = (guint8) sc->vptr->ivalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" int8 arg is '%u'\n", args[i].data.d_int8);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_FLOAT:
+ if (!sc->vptr->is_number (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_float = sc->vptr->rvalue (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" float arg is '%f'\n", args[i].data.d_float);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STRING:
+ if (!sc->vptr->is_string (sc->vptr->pair_car (a)))
+ success = FALSE;
+ if (success)
+ {
+ args[i].data.d_string = sc->vptr->string_value (sc->vptr->pair_car (a));
+#if DEBUG_MARSHALL
+ g_printerr (" string arg is '%s'\n", args[i].data.d_string);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT32 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int32array = g_new (gint32, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ /* FIXME: Check values in vector stay within range for each type. */
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int32array[j] =
+ (gint32) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int32 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 || n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT16 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name, sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int16array = g_new (gint16, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int16array[j] =
+ (gint16) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int16 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "INT8 vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_int8array = g_new (guint8, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_int8array[j] =
+ (guint8) sc->vptr->ivalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" int8 vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %ld",
+ sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "FLOAT vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_floatarray = g_new (gdouble, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+
+ if (!sc->vptr->is_number (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a number (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_floatarray[j] =
+ (gfloat) sc->vptr->rvalue (v_element);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" float vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" %f",
+ sc->vptr->rvalue ( sc->vptr->vector_elem (vector, j) ));
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ vector = sc->vptr->pair_car (a); /* vector is pointing to a list */
+ if (!sc->vptr->is_list (sc, vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i - 1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->list_length (sc, vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "STRING vector (argument %d) for function %s has "
+ "length of %d but expected length of %d",
+ i+1, proc_name,
+ sc->vptr->list_length (sc, vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_stringarray = g_new (gchar *, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->pair_car (vector);
+
+ if (!sc->vptr->is_string (v_element))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a string (argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ args[i].data.d_stringarray[j] =
+ (gchar *) sc->vptr->string_value (v_element);
+
+ vector = sc->vptr->pair_cdr (vector);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->list_length ( sc, sc->vptr->pair_car (a) );
+ g_printerr (" string vector has %ld elements\n", count);
+ if (count > 0)
+ {
+ g_printerr (" ");
+ for (j = 0; j < count; ++j)
+ g_printerr (" \"%s\"",
+ args[i].data.d_stringarray[j]);
+ g_printerr ("\n");
+ }
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_COLOR:
+ if (sc->vptr->is_string (sc->vptr->pair_car (a)))
+ {
+ if (! gimp_rgb_parse_css (&args[i].data.d_color,
+ sc->vptr->string_value (sc->vptr->pair_car (a)),
+ -1))
+ success = FALSE;
+
+ gimp_rgb_set_alpha (&args[i].data.d_color, 1.0);
+#if DEBUG_MARSHALL
+ g_printerr (" (%s)\n",
+ sc->vptr->string_value (sc->vptr->pair_car (a)));
+#endif
+ }
+ else if (sc->vptr->is_list (sc, sc->vptr->pair_car (a)) &&
+ sc->vptr->list_length (sc, sc->vptr->pair_car (a)) == 3)
+ {
+ pointer color_list;
+ guchar r = 0, g = 0, b = 0;
+
+ color_list = sc->vptr->pair_car (a);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ color_list = sc->vptr->pair_cdr (color_list);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ color_list = sc->vptr->pair_cdr (color_list);
+ if (sc->vptr->is_number (sc->vptr->pair_car (color_list)))
+ b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ else
+ success = FALSE;
+
+ if (success)
+ gimp_rgba_set_uchar (&args[i].data.d_color, r, g, b, 255);
+#if DEBUG_MARSHALL
+ if (success)
+ g_printerr (" (%d %d %d)\n", r, g, b);
+ else
+ g_printerr (" COLOR list contains non-numbers\n");
+#endif
+ }
+ else
+ {
+ success = FALSE;
+ }
+ break;
+
+ case GIMP_PDB_COLORARRAY:
+ vector = sc->vptr->pair_car (a);
+ if (!sc->vptr->is_vector (vector))
+ success = FALSE;
+ if (success)
+ {
+ n_elements = args[i-1].data.d_int32;
+ if (n_elements < 0 ||
+ n_elements > sc->vptr->vector_length (vector))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "COLOR vector (argument %d) for function %s has "
+ "size of %ld but expected size of %d",
+ i+1, proc_name,
+ sc->vptr->vector_length (vector), n_elements);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ args[i].data.d_colorarray = g_new (GimpRGB, n_elements);
+
+ for (j = 0; j < n_elements; j++)
+ {
+ pointer v_element = sc->vptr->vector_elem (vector, j);
+ pointer color_list;
+ guchar r, g, b;
+
+ if (! (sc->vptr->is_list (sc,
+ sc->vptr->pair_car (v_element)) &&
+ sc->vptr->list_length (sc,
+ sc->vptr->pair_car (v_element)) == 3))
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Item %d in vector is not a color "
+ "(argument %d for function %s)",
+ j+1, i+1, proc_name);
+ return foreign_error (sc, error_str, vector);
+ }
+
+ color_list = sc->vptr->pair_car (v_element);
+ r = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ color_list = sc->vptr->pair_cdr (color_list);
+ g = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+ color_list = sc->vptr->pair_cdr (color_list);
+ b = CLAMP (sc->vptr->ivalue (sc->vptr->pair_car (color_list)),
+ 0, 255);
+
+ gimp_rgba_set_uchar (&args[i].data.d_colorarray[j],
+ r, g, b, 255);
+ }
+#if DEBUG_MARSHALL
+ {
+ glong count = sc->vptr->vector_length (vector);
+ g_printerr (" color vector has %ld elements\n", count);
+ }
+#endif
+ }
+ break;
+
+ case GIMP_PDB_PARASITE:
+ if (!sc->vptr->is_list (sc, sc->vptr->pair_car (a)) ||
+ sc->vptr->list_length (sc, sc->vptr->pair_car (a)) != 3)
+ success = FALSE;
+ if (success)
+ {
+ pointer temp_val;
+
+ /* parasite->name */
+ temp_val = sc->vptr->pair_car (a);
+
+ if (!sc->vptr->is_string (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.name =
+ sc->vptr->string_value (sc->vptr->pair_car (temp_val));
+#if DEBUG_MARSHALL
+ g_printerr (" name '%s'\n", args[i].data.d_parasite.name);
+#endif
+
+ /* parasite->flags */
+ temp_val = sc->vptr->pair_cdr (temp_val);
+
+ if (!sc->vptr->is_number (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.flags =
+ sc->vptr->ivalue (sc->vptr->pair_car (temp_val));
+#if DEBUG_MARSHALL
+ g_printerr (" flags %d", args[i].data.d_parasite.flags);
+#endif
+
+ /* parasite->data */
+ temp_val = sc->vptr->pair_cdr (temp_val);
+
+ if (!sc->vptr->is_string (sc->vptr->pair_car (temp_val)))
+ {
+ success = FALSE;
+ break;
+ }
+
+ args[i].data.d_parasite.data =
+ sc->vptr->string_value (sc->vptr->pair_car (temp_val));
+ args[i].data.d_parasite.size = strlen (args[i].data.d_parasite.data);
+
+#if DEBUG_MARSHALL
+ g_printerr (", size %d\n", args[i].data.d_parasite.size);
+ g_printerr (" data '%s'\n", (char *)args[i].data.d_parasite.data);
+#endif
+ }
+ break;
+
+ case GIMP_PDB_STATUS:
+ return foreign_error (sc,
+ "Status is for return types, not arguments",
+ sc->vptr->pair_car (a));
+ break;
+
+ default:
+ g_snprintf (error_str, sizeof (error_str),
+ "Argument %d for %s is an unknown type",
+ i+1, proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Break out of loop before i gets updated when error was detected */
+ if (! success)
+ break;
+ }
+
+ if (success)
+ {
+ /* refuse to refresh scripts from a script, better than crashing
+ * see bug #575830
+ */
+ if (strcmp (proc_name, "script-fu-refresh-scripts"))
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" calling %s...", proc_name);
+#endif
+ values = gimp_run_procedure2 (proc_name, &nvalues, nparams, args);
+#if DEBUG_MARSHALL
+ g_printerr (" done.\n");
+#endif
+ }
+ }
+ else
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Invalid type for argument %d\n", i+1);
+#endif
+ g_snprintf (error_str, sizeof (error_str),
+ "Invalid type for argument %d to %s",
+ i+1, proc_name);
+ return foreign_error (sc, error_str, 0);
+ }
+
+ /* Check the return status */
+ if (! values)
+ {
+#if DEBUG_MARSHALL
+ g_printerr (" Did not return status\n");
+#endif
+ g_snprintf (error_str, sizeof(error_str),
+ "Procedure execution of %s did not return a status",
+ proc_name);
+
+ return foreign_error (sc, error_str, 0);
+ }
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *status_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_STATUS_TYPE,
+ values[0].data.d_status,
+ &status_name, NULL, NULL, NULL);
+ g_printerr (" return value is %s\n", status_name);
+ }
+#endif
+
+ switch (values[0].data.d_status)
+ {
+ case GIMP_PDB_EXECUTION_ERROR:
+ if (nvalues > 1 && values[1].type == GIMP_PDB_STRING)
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed: %s",
+ proc_name, values[1].data.d_string);
+ }
+ else
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed",
+ proc_name);
+ }
+ return foreign_error (sc, error_str, 0);
+ break;
+
+ case GIMP_PDB_CALLING_ERROR:
+ if (nvalues > 1 && values[1].type == GIMP_PDB_STRING)
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed on invalid input arguments: %s",
+ proc_name, values[1].data.d_string);
+ }
+ else
+ {
+ g_snprintf (error_str, sizeof (error_str),
+ "Procedure execution of %s failed on invalid input arguments",
+ proc_name);
+ }
+ return foreign_error (sc, error_str, 0);
+ break;
+
+ case GIMP_PDB_SUCCESS:
+#if DEBUG_MARSHALL
+ g_printerr (" values returned: %d\n", nvalues-1);
+#endif
+ for (i = nvalues - 2; i >= 0; --i)
+ {
+ const gchar *string;
+ gint j;
+
+#if DEBUG_MARSHALL
+ {
+ const gchar *type_name;
+
+ gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE,
+ return_vals[i].type,
+ &type_name, NULL, NULL, NULL);
+
+ g_printerr (" value %d is type %s (%d)\n",
+ i, type_name, return_vals[i].type);
+ }
+#endif
+ switch (return_vals[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int32),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT16:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int16),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT8:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc,
+ values[i + 1].data.d_int8),
+ return_val);
+ break;
+
+ case GIMP_PDB_FLOAT:
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_real (sc,
+ values[i + 1].data.d_float),
+ return_val);
+ break;
+
+ case GIMP_PDB_STRING:
+ string = values[i + 1].data.d_string;
+ if (! string)
+ string = "";
+ return_val = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc, string),
+ return_val);
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ {
+ gint32 num_int32s = values[i].data.d_int32;
+ gint32 *array = (gint32 *) values[i + 1].data.d_int32array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int32s);
+
+ for (j = 0; j < num_int32s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ {
+ gint32 num_int16s = values[i].data.d_int32;
+ gint16 *array = (gint16 *) values[i + 1].data.d_int16array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int16s);
+
+ for (j = 0; j < num_int16s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ {
+ gint32 num_int8s = values[i].data.d_int32;
+ guint8 *array = (guint8 *) values[i + 1].data.d_int8array;
+ pointer vector = sc->vptr->mk_vector (sc, num_int8s);
+
+ for (j = 0; j < num_int8s; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_integer (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ {
+ gint32 num_floats = values[i].data.d_int32;
+ gdouble *array = (gdouble *) values[i + 1].data.d_floatarray;
+ pointer vector = sc->vptr->mk_vector (sc, num_floats);
+
+ for (j = 0; j < num_floats; j++)
+ {
+ sc->vptr->set_vector_elem (vector, j,
+ sc->vptr->mk_real (sc,
+ array[j]));
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ {
+ gint num_strings = values[i].data.d_int32;
+ gchar **array = (gchar **) values[i + 1].data.d_stringarray;
+ pointer list = sc->NIL;
+
+ for (j = num_strings - 1; j >= 0; j--)
+ {
+ list = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc,
+ array[j] ?
+ array[j] : ""),
+ list);
+ }
+
+ return_val = sc->vptr->cons (sc, list, return_val);
+ }
+ break;
+
+ case GIMP_PDB_COLOR:
+ {
+ guchar r, g, b;
+ gpointer temp_val;
+
+ gimp_rgb_get_uchar (&values[i + 1].data.d_color, &r, &g, &b);
+
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, r),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, g),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, b),
+ sc->NIL)));
+ return_val = sc->vptr->cons (sc,
+ temp_val,
+ return_val);
+ break;
+ }
+
+ case GIMP_PDB_COLORARRAY:
+ {
+ gint32 num_colors = values[i].data.d_int32;
+ GimpRGB *array = (GimpRGB *) values[i + 1].data.d_colorarray;
+ pointer vector = sc->vptr->mk_vector (sc, num_colors);
+
+ for (j = 0; j < num_colors; j++)
+ {
+ guchar r, g, b;
+ pointer temp_val;
+
+ gimp_rgb_get_uchar (&array[j], &r, &g, &b);
+
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, r),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, g),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, b),
+ sc->NIL)));
+ sc->vptr->set_vector_elem (vector, j, temp_val);
+ }
+
+ return_val = sc->vptr->cons (sc, vector, return_val);
+ }
+ break;
+
+ case GIMP_PDB_PARASITE:
+ {
+ if (values[i + 1].data.d_parasite.name == NULL)
+ {
+ return_val = foreign_error (sc, "Error: null parasite", 0);
+ }
+ else
+ {
+ GimpParasite *p = &values[i + 1].data.d_parasite;
+ gchar *data = g_strndup (p->data, p->size);
+ gint char_cnt = g_utf8_strlen (data, p->size);
+ pointer temp_val;
+
+ /* don't move the mk_foo() calls outside this function call,
+ * otherwise they might be garbage collected away!
+ */
+ temp_val = sc->vptr->cons (sc,
+ sc->vptr->mk_string (sc, p->name),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_integer (sc, p->flags),
+ sc->vptr->cons (sc,
+ sc->vptr->mk_counted_string (sc,
+ data,
+ char_cnt),
+ sc->NIL)));
+ return_val = sc->vptr->cons (sc,
+ temp_val,
+ return_val);
+ g_free (data);
+
+#if DEBUG_MARSHALL
+ g_printerr (" name '%s'\n", p->name);
+ g_printerr (" flags %d", p->flags);
+ g_printerr (", size %d\n", p->size);
+ g_printerr (" data '%.*s'\n",
+ p->size, (gchar *) p->data);
+#endif
+ }
+ }
+ break;
+
+ case GIMP_PDB_STATUS:
+ return foreign_error (sc, "Procedure execution returned multiple status values", 0);
+ break;
+
+ default:
+ return foreign_error (sc, "Unknown return type", 0);
+ }
+ }
+
+ case GIMP_PDB_PASS_THROUGH:
+ case GIMP_PDB_CANCEL: /* should we do something here? */
+ break;
+ }
+
+ /* If we have no return value(s) from PDB call, return
+ * either TRUE or FALSE to indicate if call succeeded.
+ */
+ if (return_val == sc->NIL)
+ {
+ if (values[0].data.d_status == GIMP_PDB_SUCCESS)
+ return_val = sc->vptr->cons (sc, sc->T, sc->NIL);
+ else
+ return_val = sc->vptr->cons (sc, sc->F, sc->NIL);
+ }
+
+ /* free the proc name */
+ g_free (proc_name);
+
+ /* free up the executed procedure return values */
+ gimp_destroy_params (values, nvalues);
+
+ /* free up arguments and values */
+ script_fu_marshal_destroy_args (args, nparams);
+
+ /* free the query information */
+ g_free (proc_blurb);
+ g_free (proc_help);
+ g_free (proc_author);
+ g_free (proc_copyright);
+ g_free (proc_date);
+ g_free (params);
+ g_free (return_vals);
+
+ /* if we're in server mode, listen for additional commands for 10 ms */
+ if (script_fu_server_get_mode ())
+ script_fu_server_listen (10);
+
+#ifdef GDK_WINDOWING_WIN32
+ /* This seems to help a lot on Windoze. */
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+#endif
+
+ return return_val;
+}
+
+static pointer
+script_fu_marshal_procedure_call_strict (scheme *sc,
+ pointer a)
+{
+ return script_fu_marshal_procedure_call (sc, a, FALSE);
+}
+
+static pointer
+script_fu_marshal_procedure_call_permissive (scheme *sc,
+ pointer a)
+{
+ return script_fu_marshal_procedure_call (sc, a, TRUE);
+}
+
+static void
+script_fu_marshal_destroy_args (GimpParam *params,
+ gint n_params)
+{
+ gint i;
+
+ for (i = 0; i < n_params; i++)
+ {
+ switch (params[i].type)
+ {
+ case GIMP_PDB_INT32:
+ case GIMP_PDB_INT16:
+ case GIMP_PDB_INT8:
+ case GIMP_PDB_FLOAT:
+ case GIMP_PDB_STRING:
+ break;
+
+ case GIMP_PDB_INT32ARRAY:
+ g_free (params[i].data.d_int32array);
+ break;
+
+ case GIMP_PDB_INT16ARRAY:
+ g_free (params[i].data.d_int16array);
+ break;
+
+ case GIMP_PDB_INT8ARRAY:
+ g_free (params[i].data.d_int8array);
+ break;
+
+ case GIMP_PDB_FLOATARRAY:
+ g_free (params[i].data.d_floatarray);
+ break;
+
+ case GIMP_PDB_STRINGARRAY:
+ g_free (params[i].data.d_stringarray);
+ break;
+
+ case GIMP_PDB_COLORARRAY:
+ g_free (params[i].data.d_colorarray);
+ break;
+
+ case GIMP_PDB_COLOR:
+ case GIMP_PDB_DISPLAY:
+ case GIMP_PDB_IMAGE:
+ case GIMP_PDB_ITEM:
+ case GIMP_PDB_LAYER:
+ case GIMP_PDB_CHANNEL:
+ case GIMP_PDB_DRAWABLE:
+ case GIMP_PDB_SELECTION:
+ case GIMP_PDB_VECTORS:
+ case GIMP_PDB_PARASITE:
+ case GIMP_PDB_STATUS:
+ case GIMP_PDB_END:
+ break;
+ }
+ }
+
+ g_free (params);
+}
+
+static pointer
+script_fu_register_call (scheme *sc,
+ pointer a)
+{
+ return script_fu_add_script (sc, a);
+}
+
+static pointer
+script_fu_menu_register_call (scheme *sc,
+ pointer a)
+{
+ return script_fu_add_menu (sc, a);
+}
+
+static pointer
+script_fu_quit_call (scheme *sc,
+ pointer a)
+{
+ script_fu_server_quit ();
+
+ scheme_deinit (sc);
+
+ return sc->NIL;
+}
+
+static pointer
+script_fu_nil_call (scheme *sc,
+ pointer a)
+{
+ return sc->NIL;
+}
diff --git a/plug-ins/script-fu/scheme-wrapper.h b/plug-ins/script-fu/scheme-wrapper.h
new file mode 100644
index 0000000..9ab44ef
--- /dev/null
+++ b/plug-ins/script-fu/scheme-wrapper.h
@@ -0,0 +1,47 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCHEME_WRAPPER_H__
+#define __SCHEME_WRAPPER_H__
+
+#include "tinyscheme/scheme.h"
+
+void tinyscheme_init (GList *path,
+ gboolean register_scripts);
+
+void ts_set_run_mode (GimpRunMode run_mode);
+
+void ts_set_print_flag (gint print_flag);
+void ts_print_welcome (void);
+
+const gchar * ts_get_success_msg (void);
+
+void ts_interpret_stdin (void);
+
+/* if the return value is 0, success. error otherwise. */
+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/plug-ins/script-fu/script-fu-console.c b/plug-ins/script-fu/script-fu-console.c
new file mode 100644
index 0000000..835b3db
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-console.c
@@ -0,0 +1,703 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "scheme-wrapper.h"
+#include "script-fu-console.h"
+
+#include "script-fu-intl.h"
+
+
+#define TEXT_WIDTH 480
+#define TEXT_HEIGHT 400
+
+#define PROC_NAME "plug-in-script-fu-console"
+
+typedef struct
+{
+ GtkWidget *dialog;
+ GtkTextBuffer *console;
+ GtkWidget *cc;
+ GtkWidget *text_view;
+ GtkWidget *proc_browser;
+ GtkWidget *save_dialog;
+
+ GList *history;
+ gint history_len;
+ gint history_cur;
+ gint history_max;
+} ConsoleInterface;
+
+enum
+{
+ RESPONSE_CLEAR,
+ RESPONSE_SAVE
+};
+
+/*
+ * Local Functions
+ */
+static void script_fu_console_interface (void);
+static void script_fu_console_response (GtkWidget *widget,
+ gint response_id,
+ ConsoleInterface *console);
+static void script_fu_console_save_dialog (ConsoleInterface *console);
+static void script_fu_console_save_response (GtkWidget *dialog,
+ gint response_id,
+ ConsoleInterface *console);
+
+static void script_fu_browse_callback (GtkWidget *widget,
+ ConsoleInterface *console);
+static void script_fu_browse_response (GtkWidget *widget,
+ gint response_id,
+ ConsoleInterface *console);
+static void script_fu_browse_row_activated (GtkDialog *dialog);
+
+static gboolean script_fu_cc_is_empty (ConsoleInterface *console);
+static gboolean script_fu_cc_key_function (GtkWidget *widget,
+ GdkEventKey *event,
+ ConsoleInterface *console);
+
+static void script_fu_output_to_console (TsOutputType type,
+ const gchar *text,
+ gint len,
+ gpointer user_data);
+
+/*
+ * Function definitions
+ */
+
+void
+script_fu_console_run (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[1];
+
+ ts_set_print_flag (1);
+ script_fu_console_interface ();
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = GIMP_PDB_SUCCESS;
+}
+
+static void
+script_fu_console_interface (void)
+{
+ ConsoleInterface console = { 0, };
+ GtkWidget *vbox;
+ GtkWidget *button;
+ GtkWidget *scrolled_window;
+ GtkWidget *hbox;
+
+ gimp_ui_init ("script-fu", FALSE);
+
+ console.history_max = 50;
+
+ console.dialog = gimp_dialog_new (_("Script-Fu Console"),
+ "gimp-script-fu-console",
+ NULL, 0,
+ gimp_standard_help_func, PROC_NAME,
+
+ _("_Save"), RESPONSE_SAVE,
+ _("C_lear"), RESPONSE_CLEAR,
+ _("_Close"), GTK_RESPONSE_CLOSE,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (console.dialog),
+ GTK_RESPONSE_CLOSE,
+ RESPONSE_CLEAR,
+ RESPONSE_SAVE,
+ -1);
+
+ g_object_add_weak_pointer (G_OBJECT (console.dialog),
+ (gpointer) &console.dialog);
+
+ g_signal_connect (console.dialog, "response",
+ G_CALLBACK (script_fu_console_response),
+ &console);
+
+ /* The main vbox */
+ 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_get_content_area (GTK_DIALOG (console.dialog))),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ /* The output text widget */
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_ALWAYS);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+ gtk_widget_show (scrolled_window);
+
+ console.console = gtk_text_buffer_new (NULL);
+ console.text_view = gtk_text_view_new_with_buffer (console.console);
+ g_object_unref (console.console);
+
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (console.text_view), FALSE);
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (console.text_view),
+ GTK_WRAP_WORD);
+ gtk_text_view_set_left_margin (GTK_TEXT_VIEW (console.text_view), 6);
+ gtk_text_view_set_right_margin (GTK_TEXT_VIEW (console.text_view), 6);
+ gtk_widget_set_size_request (console.text_view, TEXT_WIDTH, TEXT_HEIGHT);
+ gtk_container_add (GTK_CONTAINER (scrolled_window), console.text_view);
+ gtk_widget_show (console.text_view);
+
+ gtk_text_buffer_create_tag (console.console, "strong",
+ "weight", PANGO_WEIGHT_BOLD,
+ "scale", PANGO_SCALE_LARGE,
+ NULL);
+ gtk_text_buffer_create_tag (console.console, "emphasis",
+ "style", PANGO_STYLE_OBLIQUE,
+ NULL);
+
+ {
+ const gchar * const greetings[] =
+ {
+ "strong", N_("Welcome to TinyScheme"),
+ NULL, "\n",
+ NULL, "Copyright (c) Dimitrios Souflis",
+ NULL, "\n",
+ "strong", N_("Script-Fu Console"),
+ NULL, " - ",
+ "emphasis", N_("Interactive Scheme Development"),
+ NULL, "\n"
+ };
+
+ GtkTextIter cursor;
+ gint i;
+
+ gtk_text_buffer_get_end_iter (console.console, &cursor);
+
+ for (i = 0; i < G_N_ELEMENTS (greetings); i += 2)
+ {
+ if (greetings[i])
+ gtk_text_buffer_insert_with_tags_by_name (console.console, &cursor,
+ gettext (greetings[i + 1]),
+ -1, greetings[i],
+ NULL);
+ else
+ gtk_text_buffer_insert (console.console, &cursor,
+ gettext (greetings[i + 1]), -1);
+ }
+ }
+
+ /* The current command */
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ console.cc = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), console.cc, TRUE, TRUE, 0);
+ gtk_widget_grab_focus (console.cc);
+ gtk_widget_show (console.cc);
+
+ g_signal_connect (console.cc, "key-press-event",
+ G_CALLBACK (script_fu_cc_key_function),
+ &console);
+
+ button = gtk_button_new_with_mnemonic (_("_Browse..."));
+ 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);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (script_fu_browse_callback),
+ &console);
+
+ /* Initialize the history */
+ console.history = g_list_append (console.history, NULL);
+ console.history_len = 1;
+
+ gtk_widget_show (console.dialog);
+
+ gtk_main ();
+
+ if (console.save_dialog)
+ gtk_widget_destroy (console.save_dialog);
+
+ if (console.dialog)
+ gtk_widget_destroy (console.dialog);
+}
+
+static void
+script_fu_console_response (GtkWidget *widget,
+ gint response_id,
+ ConsoleInterface *console)
+{
+ GtkTextIter start, end;
+
+ switch (response_id)
+ {
+ case RESPONSE_CLEAR:
+ gtk_text_buffer_get_start_iter (console->console, &start);
+ gtk_text_buffer_get_end_iter (console->console, &end);
+ gtk_text_buffer_delete (console->console, &start, &end);
+ break;
+
+ case RESPONSE_SAVE:
+ script_fu_console_save_dialog (console);
+ break;
+
+ default:
+ gtk_main_quit ();
+ break;
+ }
+}
+
+
+static void
+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_WINDOW (console->dialog),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (console->save_dialog),
+ GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (console->save_dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (console->save_dialog),
+ TRUE);
+
+ g_object_add_weak_pointer (G_OBJECT (console->save_dialog),
+ (gpointer) &console->save_dialog);
+
+ g_signal_connect (console->save_dialog, "response",
+ G_CALLBACK (script_fu_console_save_response),
+ console);
+ }
+
+ gtk_window_present (GTK_WINDOW (console->save_dialog));
+}
+
+static void
+script_fu_console_save_response (GtkWidget *dialog,
+ gint response_id,
+ ConsoleInterface *console)
+{
+ GtkTextIter start, end;
+
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ gchar *filename;
+ gchar *str;
+ FILE *fh;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ fh = g_fopen (filename, "w");
+
+ if (! fh)
+ {
+ g_message (_("Could not open '%s' for writing: %s"),
+ gimp_filename_to_utf8 (filename),
+ g_strerror (errno));
+
+ g_free (filename);
+ return;
+ }
+
+ gtk_text_buffer_get_start_iter (console->console, &start);
+ gtk_text_buffer_get_end_iter (console->console, &end);
+
+ str = gtk_text_buffer_get_text (console->console, &start, &end, FALSE);
+
+ fputs (str, fh);
+ fclose (fh);
+
+ g_free (str);
+ }
+
+ gtk_widget_hide (dialog);
+}
+
+static void
+script_fu_browse_callback (GtkWidget *widget,
+ ConsoleInterface *console)
+{
+ if (! console->proc_browser)
+ {
+ console->proc_browser =
+ gimp_proc_browser_dialog_new (_("Script-Fu Procedure Browser"),
+ "script-fu-procedure-browser",
+ gimp_standard_help_func, PROC_NAME,
+
+ _("_Apply"), GTK_RESPONSE_APPLY,
+ _("_Close"), GTK_RESPONSE_CLOSE,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (console->proc_browser),
+ GTK_RESPONSE_APPLY);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (console->proc_browser),
+ GTK_RESPONSE_CLOSE,
+ GTK_RESPONSE_APPLY,
+ -1);
+
+ g_object_add_weak_pointer (G_OBJECT (console->proc_browser),
+ (gpointer) &console->proc_browser);
+
+ g_signal_connect (console->proc_browser, "response",
+ G_CALLBACK (script_fu_browse_response),
+ console);
+ g_signal_connect (console->proc_browser, "row-activated",
+ G_CALLBACK (script_fu_browse_row_activated),
+ console);
+ }
+
+ gtk_window_present (GTK_WINDOW (console->proc_browser));
+}
+
+static void
+script_fu_browse_response (GtkWidget *widget,
+ gint response_id,
+ ConsoleInterface *console)
+{
+ GimpProcBrowserDialog *dialog = GIMP_PROC_BROWSER_DIALOG (widget);
+ gchar *proc_name;
+ 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;
+ gint i;
+ GString *text;
+
+ if (response_id != GTK_RESPONSE_APPLY)
+ {
+ gtk_widget_destroy (widget);
+ return;
+ }
+
+ proc_name = gimp_proc_browser_dialog_get_selected (dialog);
+
+ if (proc_name == NULL)
+ return;
+
+ gimp_procedural_db_proc_info (proc_name,
+ &proc_blurb,
+ &proc_help,
+ &proc_author,
+ &proc_copyright,
+ &proc_date,
+ &proc_type,
+ &n_params,
+ &n_return_vals,
+ &params,
+ &return_vals);
+
+ text = g_string_new ("(");
+ text = g_string_append (text, proc_name);
+
+ for (i = 0; i < n_params; i++)
+ {
+ text = g_string_append_c (text, ' ');
+ text = g_string_append (text, params[i].name);
+ }
+
+ text = g_string_append_c (text, ')');
+
+ gtk_window_set_focus (GTK_WINDOW (console->dialog), console->cc);
+
+ gtk_entry_set_text (GTK_ENTRY (console->cc), text->str);
+ gtk_editable_set_position (GTK_EDITABLE (console->cc),
+ g_utf8_pointer_to_offset (text->str,
+ text->str +
+ strlen (proc_name) + 2));
+
+ g_string_free (text, TRUE);
+
+ gtk_window_present (GTK_WINDOW (console->dialog));
+
+ g_free (proc_name);
+ 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);
+}
+
+static void
+script_fu_browse_row_activated (GtkDialog *dialog)
+{
+ gtk_dialog_response (dialog, GTK_RESPONSE_APPLY);
+}
+
+static gboolean
+script_fu_console_idle_scroll_end (GtkWidget *view)
+{
+ 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,
+ gtk_adjustment_get_upper (adj) -
+ gtk_adjustment_get_page_size (adj));
+ }
+
+ g_object_unref (view);
+
+ return FALSE;
+}
+
+static void
+script_fu_console_scroll_end (GtkWidget *view)
+{
+ /* the text view idle updates, so we need to idle scroll too
+ */
+ g_object_ref (view);
+
+ g_idle_add ((GSourceFunc) script_fu_console_idle_scroll_end, view);
+}
+
+static void
+script_fu_output_to_console (TsOutputType type,
+ const gchar *text,
+ gint len,
+ gpointer user_data)
+{
+ ConsoleInterface *console = user_data;
+
+ if (console && 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);
+ }
+ else
+ {
+ gtk_text_buffer_insert_with_tags_by_name (console->console, &cursor,
+ text, len, "emphasis",
+ NULL);
+ }
+
+ script_fu_console_scroll_end (console->text_view);
+ }
+}
+
+static gboolean
+script_fu_cc_is_empty (ConsoleInterface *console)
+{
+ const gchar *str;
+
+ if ((str = gtk_entry_get_text (GTK_ENTRY (console->cc))) == NULL)
+ return TRUE;
+
+ while (*str)
+ {
+ if (*str != ' ' && *str != '\t' && *str != '\n')
+ return FALSE;
+
+ str ++;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+script_fu_cc_key_function (GtkWidget *widget,
+ GdkEventKey *event,
+ ConsoleInterface *console)
+{
+ GList *list;
+ gint direction = 0;
+ GtkTextIter cursor;
+ GString *output;
+
+ switch (event->keyval)
+ {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_ISO_Enter:
+ if (script_fu_cc_is_empty (console))
+ return TRUE;
+
+ list = g_list_nth (console->history,
+ (g_list_length (console->history) - 1));
+
+ if (list->data)
+ g_free (list->data);
+
+ list->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (console->cc)));
+
+ gtk_text_buffer_get_end_iter (console->console, &cursor);
+
+ gtk_text_buffer_insert (console->console, &cursor, "\n", 1);
+ gtk_text_buffer_insert_with_tags_by_name (console->console, &cursor,
+ "> ", 2,
+ "strong",
+ NULL);
+
+ gtk_text_buffer_insert (console->console, &cursor,
+ gtk_entry_get_text (GTK_ENTRY (console->cc)), -1);
+ gtk_text_buffer_insert (console->console, &cursor, "\n", 1);
+
+ script_fu_console_scroll_end (console->text_view);
+
+ gtk_entry_set_text (GTK_ENTRY (console->cc), "");
+
+ 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,
+ output->str,
+ output->len,
+ console);
+ }
+ else
+ {
+ script_fu_output_to_console (TS_OUTPUT_NORMAL,
+ output->str,
+ output->len,
+ console);
+ }
+
+ gimp_plugin_set_pdb_error_handler (GIMP_PDB_ERROR_HANDLER_INTERNAL);
+
+ g_string_free (output, TRUE);
+
+ gimp_displays_flush ();
+
+ console->history = g_list_append (console->history, NULL);
+
+ if (console->history_len == console->history_max)
+ {
+ console->history = g_list_remove (console->history,
+ console->history->data);
+ if (console->history->data)
+ g_free (console->history->data);
+ }
+ else
+ {
+ console->history_len++;
+ }
+
+ console->history_cur = g_list_length (console->history) - 1;
+
+ return TRUE;
+ break;
+
+ case GDK_KEY_KP_Up:
+ case GDK_KEY_Up:
+ direction = -1;
+ break;
+
+ case GDK_KEY_KP_Down:
+ case GDK_KEY_Down:
+ direction = 1;
+ break;
+
+ case GDK_KEY_P:
+ case GDK_KEY_p:
+ if (event->state & GDK_CONTROL_MASK)
+ direction = -1;
+ break;
+
+ case GDK_KEY_N:
+ case GDK_KEY_n:
+ if (event->state & GDK_CONTROL_MASK)
+ direction = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (direction)
+ {
+ /* Make sure we keep track of the current one */
+ if (console->history_cur == g_list_length (console->history) - 1)
+ {
+ list = g_list_nth (console->history, console->history_cur);
+
+ g_free (list->data);
+ list->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (console->cc)));
+ }
+
+ console->history_cur += direction;
+
+ if (console->history_cur < 0)
+ console->history_cur = 0;
+
+ if (console->history_cur >= console->history_len)
+ console->history_cur = console->history_len - 1;
+
+ gtk_entry_set_text (GTK_ENTRY (console->cc),
+ (gchar *) (g_list_nth (console->history,
+ console->history_cur))->data);
+
+ gtk_editable_set_position (GTK_EDITABLE (console->cc), -1);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/plug-ins/script-fu/script-fu-console.h b/plug-ins/script-fu/script-fu-console.h
new file mode 100644
index 0000000..8410a61
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-console.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 <https://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);
+
+
+#endif /* __SCRIPT_FU_CONSOLE_H__ */
diff --git a/plug-ins/script-fu/script-fu-enums.h b/plug-ins/script-fu/script-fu-enums.h
new file mode 100644
index 0000000..581441f
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-enums.h
@@ -0,0 +1,54 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_ENUMS_H__
+#define __SCRIPT_FU_ENUMS_H__
+
+/* Typedefs for script-fu argument types */
+
+typedef enum
+{
+ SF_IMAGE = 0,
+ SF_DRAWABLE,
+ SF_LAYER,
+ SF_CHANNEL,
+ SF_VECTORS,
+ SF_COLOR,
+ SF_TOGGLE,
+ SF_VALUE,
+ SF_STRING,
+ SF_ADJUSTMENT,
+ SF_FONT,
+ SF_PATTERN,
+ SF_BRUSH,
+ SF_GRADIENT,
+ SF_FILENAME,
+ SF_DIRNAME,
+ SF_OPTION,
+ SF_PALETTE,
+ SF_TEXT,
+ SF_ENUM,
+ SF_DISPLAY
+} SFArgType;
+
+typedef enum
+{
+ SF_SLIDER = 0,
+ SF_SPINNER
+} SFAdjustmentType;
+
+#endif /* __SCRIPT_FU_ENUMS__ */
diff --git a/plug-ins/script-fu/script-fu-eval.c b/plug-ins/script-fu/script-fu-eval.c
new file mode 100644
index 0000000..6f2e354
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "libgimp/gimp.h"
+
+#include "scheme-wrapper.h"
+#include "script-fu-eval.h"
+
+#include "script-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, _("Script-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/plug-ins/script-fu/script-fu-eval.h b/plug-ins/script-fu/script-fu-eval.h
new file mode 100644
index 0000000..83ec9c4
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://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/plug-ins/script-fu/script-fu-interface.c b/plug-ins/script-fu/script-fu-interface.c
new file mode 100644
index 0000000..0fa1811
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-interface.c
@@ -0,0 +1,1070 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#ifdef GDK_WINDOWING_QUARTZ
+#import <Cocoa/Cocoa.h>
+#elif defined (G_OS_WIN32)
+#include <windows.h>
+#endif
+
+#include "tinyscheme/scheme-private.h"
+#include "scheme-wrapper.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-interface.h"
+#include "script-fu-scripts.h"
+#include "script-fu-script.h"
+
+#include "script-fu-intl.h"
+
+
+#define RESPONSE_RESET 1
+
+#define TEXT_WIDTH 100
+#define COLOR_SAMPLE_WIDTH 60
+#define COLOR_SAMPLE_HEIGHT 15
+#define SLIDER_WIDTH 80
+
+
+typedef struct
+{
+ GtkWidget *dialog;
+
+ GtkWidget *table;
+ GtkWidget **widgets;
+
+ GtkWidget *progress_label;
+ GtkWidget *progress_bar;
+
+ gchar *title;
+ gchar *last_command;
+ gint command_count;
+ gint consec_command_count;
+} SFInterface;
+
+
+/*
+ * Local Functions
+ */
+
+static void script_fu_interface_quit (SFScript *script);
+
+static void script_fu_response (GtkWidget *widget,
+ gint response_id,
+ SFScript *script);
+static void script_fu_ok (SFScript *script);
+static void script_fu_reset (SFScript *script);
+
+static void script_fu_file_callback (GtkWidget *widget,
+ SFFilename *file);
+static void script_fu_combo_callback (GtkWidget *widget,
+ SFOption *option);
+static void script_fu_pattern_callback (gpointer data,
+ const gchar *name,
+ gint width,
+ gint height,
+ gint bytes,
+ const guchar *mask_data,
+ gboolean closing);
+static void script_fu_gradient_callback (gpointer data,
+ const gchar *name,
+ gint width,
+ const gdouble *mask_data,
+ gboolean closing);
+static void script_fu_font_callback (gpointer data,
+ const gchar *name,
+ gboolean closing);
+static void script_fu_palette_callback (gpointer data,
+ const gchar *name,
+ gboolean closing);
+static void script_fu_brush_callback (gpointer data,
+ const gchar *name,
+ gdouble opacity,
+ gint spacing,
+ GimpLayerMode paint_mode,
+ gint width,
+ gint height,
+ const guchar *mask_data,
+ gboolean closing);
+static void script_fu_flush_events (void);
+static void script_fu_activate_main_dialog (void);
+
+
+/*
+ * Local variables
+ */
+
+static SFInterface *sf_interface = NULL; /* there can only be at most
+ * one interactive interface
+ */
+
+static GimpPDBStatusType sf_status = GIMP_PDB_SUCCESS;
+
+
+/*
+ * Function definitions
+ */
+
+gboolean
+script_fu_interface_is_active (void)
+{
+ return (sf_interface != NULL);
+}
+
+void
+script_fu_interface_report_cc (const gchar *command)
+{
+ if (sf_interface == NULL)
+ return;
+
+ if (sf_interface->last_command &&
+ strcmp (sf_interface->last_command, command) == 0)
+ {
+ sf_interface->command_count++;
+
+ if (! g_str_has_prefix (command, "gimp-progress-"))
+ {
+ gchar *new_command;
+
+ new_command = g_strdup_printf ("%s <%d>",
+ command, sf_interface->command_count);
+ gtk_label_set_text (GTK_LABEL (sf_interface->progress_label),
+ new_command);
+ g_free (new_command);
+ }
+ }
+ else
+ {
+ sf_interface->command_count = 1;
+
+ g_free (sf_interface->last_command);
+ sf_interface->last_command = g_strdup (command);
+
+ if (! g_str_has_prefix (command, "gimp-progress-"))
+ {
+ gtk_label_set_text (GTK_LABEL (sf_interface->progress_label),
+ command);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (sf_interface->progress_label), "");
+ }
+ }
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+GimpPDBStatusType
+script_fu_interface (SFScript *script,
+ gint start_arg)
+{
+ GtkWidget *dialog;
+ GtkWidget *vbox;
+ GtkWidget *vbox2;
+ GtkSizeGroup *group;
+ GSList *list;
+ 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.
+ */
+ if (sf_interface != NULL)
+ {
+ gchar *message =
+ g_strdup_printf ("%s\n\n%s",
+ _("Script-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 GIMP_PDB_CANCEL;
+ }
+
+ g_return_val_if_fail (script != NULL, FALSE);
+
+ if (!gtk_initted)
+ {
+ INIT_I18N();
+
+ gimp_ui_init ("script-fu", TRUE);
+
+ gtk_initted = TRUE;
+ }
+
+ sf_status = GIMP_PDB_SUCCESS;
+
+ sf_interface = g_slice_new0 (SFInterface);
+
+ 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);
+
+ sf_interface->dialog = dialog =
+ gimp_dialog_new (title, "gimp-script-fu",
+ NULL, 0,
+ gimp_standard_help_func, script->name,
+
+ _("_Reset"), RESPONSE_RESET,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_OK"), GTK_RESPONSE_OK,
+
+ NULL);
+ g_free (title);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ RESPONSE_RESET,
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (script_fu_response),
+ script);
+
+ g_signal_connect_swapped (dialog, "destroy",
+ G_CALLBACK (script_fu_interface_quit),
+ script);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+
+ 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_get_content_area (GTK_DIALOG (dialog))),
+ vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ /* The argument table */
+ 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);
+ gtk_box_pack_start (GTK_BOX (vbox), sf_interface->table, FALSE, FALSE, 0);
+ gtk_widget_show (sf_interface->table);
+
+ group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ for (i = start_arg; i < script->n_args; i++)
+ {
+ GtkWidget *widget = NULL;
+ gchar *label_text;
+ gfloat label_yalign = 0.5;
+ 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:"), arg->label);
+
+ 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:
+ {
+ GimpColorConfig *config;
+
+ left_align = TRUE;
+ widget = gimp_color_button_new (_("Script-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);
+
+ config = gimp_get_color_configuration ();
+ gimp_color_button_set_color_config (GIMP_COLOR_BUTTON (widget),
+ config);
+ g_object_unref (config);
+
+ g_signal_connect (widget, "color-changed",
+ G_CALLBACK (gimp_color_button_get_color),
+ &arg->value.sfa_color);
+ }
+ break;
+
+ case SF_TOGGLE:
+ g_free (label_text);
+ label_text = NULL;
+ widget = gtk_check_button_new_with_mnemonic (arg->label);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
+ arg->value.sfa_toggle);
+
+ 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);
+
+ 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);
+
+ view = gtk_text_view_new ();
+ gtk_container_add (GTK_CONTAINER (widget), view);
+ gtk_widget_show (view);
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (view), TRUE);
+
+ gtk_text_buffer_set_text (buffer, arg->value.sfa_value, -1);
+
+ label_yalign = 0.0;
+ }
+ break;
+
+ 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;
+ arg->value.sfa_adjustment.adj = (GtkAdjustment *)
+ gtk_adjustment_new (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);
+ widget = gimp_spin_button_new (arg->value.sfa_adjustment.adj,
+ arg->default_value.sfa_adjustment.step,
+ arg->default_value.sfa_adjustment.digits);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ break;
+ }
+
+ g_signal_connect (arg->value.sfa_adjustment.adj,
+ "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &arg->value.sfa_adjustment.value);
+ break;
+
+ case SF_FILENAME:
+ case SF_DIRNAME:
+ if (arg->type == SF_FILENAME)
+ widget = gtk_file_chooser_button_new (_("Script-Fu File Selection"),
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ else
+ widget = gtk_file_chooser_button_new (_("Script-Fu Folder Selection"),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
+
+ if (arg->value.sfa_file.filename)
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
+ arg->value.sfa_file.filename);
+
+ g_signal_connect (widget, "selection-changed",
+ G_CALLBACK (script_fu_file_callback),
+ &arg->value.sfa_file);
+ break;
+
+ case SF_FONT:
+ widget = gimp_font_select_button_new (_("Script-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_PALETTE:
+ widget = gimp_palette_select_button_new (_("Script-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_PATTERN:
+ left_align = TRUE;
+ widget = gimp_pattern_select_button_new (_("Script-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_GRADIENT:
+ left_align = TRUE;
+ widget = gimp_gradient_select_button_new (_("Script-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_BRUSH:
+ left_align = TRUE;
+ widget = gimp_brush_select_button_new (_("Script-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;
+
+ 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),
+ list->data);
+ }
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget),
+ arg->value.sfa_option.history);
+
+ g_signal_connect (widget, "changed",
+ G_CALLBACK (script_fu_combo_callback),
+ &arg->value.sfa_option);
+ break;
+
+ case SF_ENUM:
+ widget = gimp_enum_combo_box_new (g_type_from_name (arg->default_value.sfa_enum.type_name));
+
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget),
+ arg->value.sfa_enum.history);
+
+ 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)
+ {
+ if (label_text)
+ {
+ gimp_table_attach_aligned (GTK_TABLE (sf_interface->table),
+ 0, row,
+ label_text, 0.0, label_yalign,
+ widget, 2, left_align);
+ g_free (label_text);
+ }
+ else
+ {
+ gtk_table_attach (GTK_TABLE (sf_interface->table),
+ widget, 0, 3, row, row + 1,
+ GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+ }
+
+ if (left_align)
+ gtk_size_group_add_widget (group, widget);
+ }
+
+ sf_interface->widgets[i] = widget;
+ }
+
+ g_object_unref (group);
+
+ /* the script progress bar */
+ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_end (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
+ gtk_widget_show (vbox2);
+
+ sf_interface->progress_bar = gimp_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox2), sf_interface->progress_bar,
+ FALSE, FALSE, 0);
+ gtk_widget_show (sf_interface->progress_bar);
+
+ sf_interface->progress_label = gtk_label_new (NULL);
+ gtk_label_set_xalign (GTK_LABEL (sf_interface->progress_label), 0.0);
+ gtk_label_set_ellipsize (GTK_LABEL (sf_interface->progress_label),
+ PANGO_ELLIPSIZE_MIDDLE);
+ gimp_label_set_attributes (GTK_LABEL (sf_interface->progress_label),
+ PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
+ -1);
+ gtk_box_pack_start (GTK_BOX (vbox2), sf_interface->progress_label,
+ FALSE, FALSE, 0);
+ gtk_widget_show (sf_interface->progress_label);
+#ifdef G_OS_WIN32
+ {
+ HWND foreground = GetForegroundWindow ();
+#endif
+
+ gtk_widget_show (dialog);
+
+ gtk_main ();
+
+#ifdef G_OS_WIN32
+ if (! GetForegroundWindow ())
+ SetForegroundWindow (foreground);
+ }
+#endif
+ return sf_status;
+}
+
+static void
+script_fu_interface_quit (SFScript *script)
+{
+ gint i;
+
+ g_return_if_fail (script != NULL);
+ g_return_if_fail (sf_interface != NULL);
+
+ g_free (sf_interface->title);
+
+ for (i = 0; i < script->n_args; i++)
+ switch (script->args[i].type)
+ {
+ case SF_FONT:
+ case SF_PALETTE:
+ case SF_PATTERN:
+ case SF_GRADIENT:
+ case SF_BRUSH:
+ gimp_select_button_close_popup
+ (GIMP_SELECT_BUTTON (sf_interface->widgets[i]));
+ break;
+
+ default:
+ break;
+ }
+
+ g_free (sf_interface->widgets);
+ g_free (sf_interface->last_command);
+
+ g_slice_free (SFInterface, sf_interface);
+ sf_interface = NULL;
+
+ /* 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!
+ */
+
+ gtk_main_quit ();
+}
+
+static void
+script_fu_file_callback (GtkWidget *widget,
+ SFFilename *file)
+{
+ if (file->filename)
+ g_free (file->filename);
+
+ file->filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+ script_fu_activate_main_dialog ();
+}
+
+static void
+script_fu_combo_callback (GtkWidget *widget,
+ SFOption *option)
+{
+ option->history = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+}
+
+static void
+script_fu_string_update (gchar **dest,
+ const gchar *src)
+{
+ if (*dest)
+ g_free (*dest);
+
+ *dest = g_strdup (src);
+}
+
+static void
+script_fu_pattern_callback (gpointer data,
+ const gchar *name,
+ gint width,
+ gint height,
+ gint bytes,
+ const guchar *mask_data,
+ gboolean closing)
+{
+ script_fu_string_update (data, name);
+ if (closing) script_fu_activate_main_dialog ();
+}
+
+static void
+script_fu_gradient_callback (gpointer data,
+ const gchar *name,
+ gint width,
+ const gdouble *mask_data,
+ gboolean closing)
+{
+ script_fu_string_update (data, name);
+ if (closing) script_fu_activate_main_dialog ();
+}
+
+static void
+script_fu_font_callback (gpointer data,
+ const gchar *name,
+ gboolean closing)
+{
+ script_fu_string_update (data, name);
+ if (closing) script_fu_activate_main_dialog ();
+}
+
+static void
+script_fu_palette_callback (gpointer data,
+ const gchar *name,
+ gboolean closing)
+{
+ script_fu_string_update (data, name);
+ if (closing) script_fu_activate_main_dialog ();
+}
+
+static void
+script_fu_brush_callback (gpointer data,
+ const gchar *name,
+ gdouble opacity,
+ gint spacing,
+ GimpLayerMode paint_mode,
+ gint width,
+ gint height,
+ const guchar *mask_data,
+ gboolean closing)
+{
+ SFBrush *brush = data;
+
+ g_free (brush->name);
+
+ brush->name = g_strdup (name);
+ brush->opacity = opacity;
+ brush->spacing = spacing;
+ brush->paint_mode = paint_mode;
+
+ if (closing) script_fu_activate_main_dialog ();
+}
+
+static void
+unset_transient_for (GtkWidget *dialog)
+{
+ GdkWindow *window = gtk_widget_get_window (dialog);
+
+ if (window)
+ gdk_property_delete (window,
+ gdk_atom_intern_static_string ("WM_TRANSIENT_FOR"));
+}
+
+static void
+script_fu_response (GtkWidget *widget,
+ gint response_id,
+ SFScript *script)
+{
+ 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)
+ {
+ case RESPONSE_RESET:
+ script_fu_reset (script);
+ break;
+
+ case GTK_RESPONSE_OK:
+ gtk_widget_set_sensitive (sf_interface->table, FALSE);
+ gtk_widget_set_sensitive (action_area, FALSE);
+
+ script_fu_ok (script);
+
+ script_fu_flush_events ();
+ /*
+ * The script could have created a new GimpImageWindow, so
+ * unset the transient-for property not to focus the
+ * ImageWindow from which the script was started
+ */
+ unset_transient_for (sf_interface->dialog);
+
+ gtk_widget_destroy (sf_interface->dialog);
+ break;
+
+ default:
+ sf_status = GIMP_PDB_CANCEL;
+
+ script_fu_flush_events ();
+ gtk_widget_destroy (sf_interface->dialog);
+ break;
+ }
+
+ script_fu_flush_events ();
+}
+
+static void
+script_fu_ok (SFScript *script)
+{
+ GString *output;
+ gchar *command;
+ gint i;
+
+ for (i = 0; i < script->n_args; i++)
+ {
+ SFArgValue *arg_value = &script->args[i].value;
+ GtkWidget *widget = sf_interface->widgets[i];
+
+ switch (script->args[i].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:
+ g_free (arg_value->sfa_value);
+ arg_value->sfa_value =
+ g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
+ break;
+
+ case SF_TEXT:
+ {
+ GtkWidget *view;
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+
+ view = gtk_bin_get_child (GTK_BIN (widget));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_buffer_get_start_iter (buffer, &start);
+ gtk_text_buffer_get_end_iter (buffer, &end);
+
+ g_free (arg_value->sfa_value);
+ arg_value->sfa_value = gtk_text_buffer_get_text (buffer,
+ &start, &end,
+ FALSE);
+ }
+ break;
+
+ case SF_ADJUSTMENT:
+ case SF_FILENAME:
+ case SF_DIRNAME:
+ case SF_FONT:
+ case SF_PALETTE:
+ case SF_PATTERN:
+ case SF_GRADIENT:
+ case SF_BRUSH:
+ case SF_OPTION:
+ case SF_ENUM:
+ break;
+ }
+ }
+
+ command = script_fu_script_get_command (script);
+
+ /* run the command through the interpreter */
+ 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))
+ {
+ 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);
+}
+
+static void
+script_fu_reset (SFScript *script)
+{
+ gint i;
+
+ script_fu_script_reset (script, FALSE);
+
+ for (i = 0; i < script->n_args; i++)
+ {
+ SFArgValue *value = &script->args[i].value;
+ GtkWidget *widget = sf_interface->widgets[i];
+
+ switch (script->args[i].type)
+ {
+ case SF_IMAGE:
+ case SF_DRAWABLE:
+ case SF_LAYER:
+ case SF_CHANNEL:
+ case SF_VECTORS:
+ case SF_DISPLAY:
+ break;
+
+ case SF_COLOR:
+ gimp_color_button_set_color (GIMP_COLOR_BUTTON (widget),
+ &value->sfa_color);
+ break;
+
+ case SF_TOGGLE:
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
+ value->sfa_toggle);
+ break;
+
+ case SF_VALUE:
+ case SF_STRING:
+ gtk_entry_set_text (GTK_ENTRY (widget), value->sfa_value);
+ break;
+
+ case SF_TEXT:
+ {
+ GtkWidget *view;
+ GtkTextBuffer *buffer;
+
+ view = gtk_bin_get_child (GTK_BIN (widget));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_buffer_set_text (buffer, value->sfa_value, -1);
+ }
+ break;
+
+ case SF_ADJUSTMENT:
+ 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),
+ value->sfa_file.filename);
+ break;
+
+ case SF_FONT:
+ gimp_font_select_button_set_font (GIMP_FONT_SELECT_BUTTON (widget),
+ value->sfa_font);
+ break;
+
+ case SF_PALETTE:
+ gimp_palette_select_button_set_palette (GIMP_PALETTE_SELECT_BUTTON (widget),
+ value->sfa_palette);
+ break;
+
+ case SF_PATTERN:
+ gimp_pattern_select_button_set_pattern (GIMP_PATTERN_SELECT_BUTTON (widget),
+ value->sfa_pattern);
+ break;
+
+ case SF_GRADIENT:
+ gimp_gradient_select_button_set_gradient (GIMP_GRADIENT_SELECT_BUTTON (widget),
+ value->sfa_gradient);
+ break;
+
+ case SF_BRUSH:
+ gimp_brush_select_button_set_brush (GIMP_BRUSH_SELECT_BUTTON (widget),
+ 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),
+ value->sfa_option.history);
+ break;
+
+ case SF_ENUM:
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget),
+ value->sfa_enum.history);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Functions for window front/back management.
+ * These might only be necessary for MacOS.
+ *
+ * One problem is that the GIMP and the scriptfu extension process are separate "apps".
+ * Closing a main scriptfu dialog does not terminate the scriptfu extension process,
+ * and MacOS does not then activate some other app.
+ * On other platforms, the select dialogs are transient to the GIMP app's progress bar,
+ * but that doesn't seem to work on MacOS.
+ *
+ * Also some of the GIMP "select" widgets (for brush, pattern, gradient, font, palette)
+ * for plugins are independent and tool like:
+ * their popup dialog window is not a child of the button which pops it up.
+ * The button "owns" the popup but GDK is not aware of that relation,
+ * and so does not handle closing automatically.
+ * There are PDB callbacks in each direction:
+ * from the select dialog to the scriptfu extension on user's new selection
+ * from the scriptfu extension to the select dialog on closing
+ *
+ * This might change in the future.
+ * 1) in GIMP 3, scriptfu and python plugins should use a common API for a control dialog,
+ * (script-fu-interface.c is obsoleted?)
+ * 2) the code for select dialogs is significantly changed in GIMP 3
+ * 3) Gtk3 might solve this (now using Gtk2.)
+ */
+
+/* On MacOS, without calls to this, scriptfu dialog gets spinning ball of doom,
+ * meaning MacOS thinks app is not responding to events,
+ * and dialog stays visible even after destroyed.
+ */
+static void
+script_fu_flush_events (void)
+{
+ /* Ensure all GLib events have been processed. */
+
+ /* Former code also hid GUI of the script-fu extension process using: [NSApp hide: nil];
+ * (In Objective-C, get instance of NSApplication and send it a "hide" message with nil sender.)
+ * Hiding is not necessary, since this is only called when
+ * scriptfu is done interpreting the current script and is destroying its widgets.
+ */
+#ifdef GDK_WINDOWING_QUARTZ
+ /* Alternative code might be a call to gtk_main()?
+ * This is not an infinite loop since there are finite events, and iteration reduces them.
+ * Somehow, this lets MacOS think the app is responsive.
+ */
+ while (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, TRUE);
+#else
+ /* empty function, optimized out. */
+#endif
+}
+
+
+/* On MacOS, without calls to this,
+ * when user closes GIMP "select" dialogs (child of main dialog)
+ * the main scriptfu dialog can be obscured by GIMP main window.
+ * The main scriptfu dialog must be visible so user can choose the OK button,
+ * and it contains a progress bar.
+ *
+ * Note the color "select" dialog has no callback specialized for scriptfu.
+ * And the file "chooser" dialog is also different.
+ */
+static void
+script_fu_activate_main_dialog (void)
+{
+ /* Ensure the main dialog of the script-fu extension process is not obscured. */
+#ifdef GDK_WINDOWING_QUARTZ
+ /* In Objective-C, get instance of NSApplication
+ * and send it a "activateIgnoringOtherApps" message, i.e. bring to front.
+ */
+ [NSApp activateIgnoringOtherApps: YES];
+#else
+ /* empty function, optimized out. */
+#endif
+}
diff --git a/plug-ins/script-fu/script-fu-interface.h b/plug-ins/script-fu/script-fu-interface.h
new file mode 100644
index 0000000..3d5091c
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-interface.h
@@ -0,0 +1,28 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_INTERFACE_H__
+#define __SCRIPT_FU_INTERFACE_H__
+
+
+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/plug-ins/script-fu/script-fu-intl.h b/plug-ins/script-fu/script-fu-intl.h
new file mode 100644
index 0000000..462582c
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-intl.h
@@ -0,0 +1,43 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * script-fu-intl.h
+ *
+ * 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 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see
+ * <https://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"
+#endif
+
+#include <glib/gi18n.h>
+
+
+#ifndef HAVE_BIND_TEXTDOMAIN_CODESET
+# define bind_textdomain_codeset(Domain, Codeset) (Domain)
+#endif
+
+#define INIT_I18N() G_STMT_START{ \
+ bindtextdomain (GETTEXT_PACKAGE"-script-fu", \
+ gimp_locale_directory ()); \
+ bind_textdomain_codeset (GETTEXT_PACKAGE"-script-fu", "UTF-8"); \
+ textdomain (GETTEXT_PACKAGE"-script-fu"); \
+}G_STMT_END
+
+
+#endif /* __SCRIPT_FU_INTL_H__ */
diff --git a/plug-ins/script-fu/script-fu-regex.c b/plug-ins/script-fu/script-fu-regex.c
new file mode 100644
index 0000000..02255d2
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-regex.c
@@ -0,0 +1,179 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* 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 "script-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;
+ gboolean is_valid_utf8;
+ 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);
+
+ is_valid_utf8 = g_utf8_validate (string, -1, NULL);
+
+ 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);
+
+ if (is_valid_utf8)
+ {
+ start = g_utf8_pointer_to_offset (string, string + start);
+ end = g_utf8_pointer_to_offset (string, string + 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/plug-ins/script-fu/script-fu-regex.h b/plug-ins/script-fu/script-fu-regex.h
new file mode 100644
index 0000000..9c0cbb2
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://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/plug-ins/script-fu/script-fu-script.c b/plug-ins/script-fu/script-fu-script.c
new file mode 100644
index 0000000..cd37163
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "tinyscheme/scheme-private.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-script.h"
+#include "script-fu-scripts.h"
+#include "script-fu-utils.h"
+
+#include "script-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 (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/plug-ins/script-fu/script-fu-script.h b/plug-ins/script-fu/script-fu-script.h
new file mode 100644
index 0000000..86b318f
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://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/plug-ins/script-fu/script-fu-scripts.c b/plug-ins/script-fu/script-fu-scripts.c
new file mode 100644
index 0000000..bf56edb
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-scripts.c
@@ -0,0 +1,934 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "tinyscheme/scheme-private.h"
+
+#include "scheme-wrapper.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-interface.h"
+#include "script-fu-script.h"
+#include "script-fu-scripts.h"
+#include "script-fu-utils.h"
+
+#include "script-fu-intl.h"
+
+
+typedef struct
+{
+ SFScript *script;
+ gchar *menu_path;
+} SFMenu;
+
+
+/*
+ * Local Functions
+ */
+
+static gboolean script_fu_run_command (const gchar *command,
+ GError **error);
+static void script_fu_load_directory (GFile *directory);
+static void script_fu_load_script (GFile *file);
+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);
+
+
+/*
+ * Local variables
+ */
+
+static GTree *script_tree = NULL;
+static GList *script_menu_list = NULL;
+
+
+/*
+ * Function definitions
+ */
+
+void
+script_fu_find_scripts (GList *path)
+{
+ GList *list;
+
+ /* Make sure to clear any existing scripts */
+ if (script_tree != NULL)
+ {
+ g_tree_foreach (script_tree,
+ (GTraverseFunc) script_fu_remove_script,
+ NULL);
+ g_tree_destroy (script_tree);
+ }
+
+ if (! path)
+ return;
+
+ script_tree = g_tree_new ((GCompareFunc) g_utf8_collate);
+
+ for (list = path; list; list = g_list_next (list))
+ {
+ script_fu_load_directory (list->data);
+ }
+
+ /* Now that all scripts are read in and sorted, tell gimp about them */
+ g_tree_foreach (script_tree,
+ (GTraverseFunc) script_fu_install_script,
+ NULL);
+
+ script_menu_list = g_list_sort (script_menu_list,
+ (GCompareFunc) script_fu_menu_compare);
+
+ /* 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)
+{
+ 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' call"));
+ return sc->NIL;
+ }
+
+ /* Find the script name */
+ name = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (a);
+
+ /* 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 */
+ blurb = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (a);
+
+ /* Find the script author */
+ author = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (a);
+
+ /* Find the script copyright */
+ copyright = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (a);
+
+ /* Find the script date */
+ 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))
+ {
+ image_types = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (a);
+ }
+ else
+ {
+ image_types = sc->vptr->string_value (a);
+ a = sc->NIL;
+ }
+
+ /* Check the supplied number of arguments */
+ n_args = sc->vptr->list_length (sc, a) / 3;
+
+ /* 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];
+
+ 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);
+
+ 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 (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: default IDs must be integer values", 0);
+
+ arg->default_value.sfa_image =
+ sc->vptr->ivalue (sc->vptr->pair_car (a));
+ break;
+
+ case SF_COLOR:
+ if (sc->vptr->is_string (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.
+ */
+ gchar *filename = arg->default_value.sfa_file.filename;
+
+ while (*filename)
+ {
+ if (*filename == '/')
+ *filename = G_DIR_SEPARATOR;
+
+ filename++;
+ }
+ }
+#endif
+ 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);
+
+ 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);
+ }
+ }
+
+ /* fill all values from defaults */
+ script_fu_script_reset (script, TRUE);
+
+ 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;
+ }
+ }
+
+ {
+ GList *list = g_tree_lookup (script_tree, script->menu_label);
+
+ g_tree_insert (script_tree, (gpointer) script->menu_label,
+ g_list_append (list, script));
+ }
+
+ return sc->NIL;
+}
+
+pointer
+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)
+ return foreign_error (sc, "Incorrect number of arguments for script-fu-menu-register", 0);
+
+ /* Find the script PDB entry name */
+ name = sc->vptr->string_value (sc->vptr->pair_car (a));
+ a = sc->vptr->pair_cdr (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;
+ }
+
+ /* Create a new list of menus */
+ menu = g_slice_new0 (SFMenu);
+
+ menu->script = script;
+
+ /* Find the script menu path */
+ 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;
+}
+
+
+/* private functions */
+
+static gboolean
+script_fu_run_command (const gchar *command,
+ GError **error)
+{
+ GString *output;
+ gboolean success = FALSE;
+
+ output = g_string_new (NULL);
+ ts_register_output_func (ts_gstring_output_func, output);
+
+ 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_directory (GFile *directory)
+{
+ GFileEnumerator *enumerator;
+
+ enumerator = g_file_enumerate_children (directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ if (enumerator)
+ {
+ GFileInfo *info;
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
+ {
+ GFileType file_type = g_file_info_get_file_type (info);
+
+ if ((file_type == G_FILE_TYPE_REGULAR ||
+ file_type == G_FILE_TYPE_DIRECTORY) &&
+ ! g_file_info_get_is_hidden (info))
+ {
+ GFile *child = g_file_enumerator_get_child (enumerator, info);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY)
+ script_fu_load_directory (child);
+ else
+ script_fu_load_script (child);
+
+ g_object_unref (child);
+ }
+
+ g_object_unref (info);
+ }
+
+ g_object_unref (enumerator);
+ }
+}
+
+static void
+script_fu_load_script (GFile *file)
+{
+ if (gimp_file_has_extension (file, ".scm"))
+ {
+ gchar *path = g_file_get_path (file);
+ gchar *escaped = script_fu_strescape (path);
+ gchar *command;
+ GError *error = NULL;
+
+ command = g_strdup_printf ("(load \"%s\")", escaped);
+ g_free (escaped);
+
+ if (! script_fu_run_command (command, &error))
+ {
+ gchar *message = g_strdup_printf (_("Error while loading %s:"),
+ gimp_file_get_utf8_name (file));
+
+ g_message ("%s\n\n%s", message, error->message);
+
+ g_clear_error (&error);
+ g_free (message);
+ }
+
+#ifdef G_OS_WIN32
+ /* No, I don't know why, but this is
+ * necessary on NT 4.0.
+ */
+ Sleep (0);
+#endif
+
+ g_free (command);
+ g_free (path);
+ }
+}
+
+/*
+ * The following function is a GTraverseFunction.
+ */
+static gboolean
+script_fu_install_script (gpointer foo G_GNUC_UNUSED,
+ GList *scripts,
+ gpointer bar G_GNUC_UNUSED)
+{
+ GList *list;
+
+ for (list = scripts; list; list = g_list_next (list))
+ {
+ SFScript *script = list->data;
+
+ script_fu_script_install_proc (script, script_fu_script_proc);
+ }
+
+ return FALSE;
+}
+
+static void
+script_fu_install_menu (SFMenu *menu)
+{
+ gimp_plugin_menu_register (menu->script->name, menu->menu_path);
+
+ g_free (menu->menu_path);
+ g_slice_free (SFMenu, menu);
+}
+
+/*
+ * The following function is a GTraverseFunction.
+ */
+static gboolean
+script_fu_remove_script (gpointer foo G_GNUC_UNUSED,
+ GList *scripts,
+ gpointer bar G_GNUC_UNUSED)
+{
+ GList *list;
+
+ for (list = scripts; list; list = g_list_next (list))
+ {
+ SFScript *script = list->data;
+
+ script_fu_script_uninstall_proc (script);
+ script_fu_script_free (script);
+ }
+
+ g_list_free (scripts);
+
+ return FALSE;
+}
+
+static void
+script_fu_script_proc (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ 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);
+
+ if (! script)
+ status = GIMP_PDB_CALLING_ERROR;
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ GimpRunMode run_mode = params[0].data.d_int32;
+
+ ts_set_run_mode (run_mode);
+
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ {
+ gint min_args = 0;
+
+ /* First, try to collect the standard script arguments... */
+ min_args = script_fu_script_collect_standard_args (script,
+ nparams, params);
+
+ /* ...then acquire the rest of arguments (if any) with a dialog */
+ if (script->n_args > min_args)
+ {
+ status = script_fu_interface (script, min_args);
+ break;
+ }
+ /* otherwise (if the script takes no more arguments), skip
+ * this part and run the script directly (fallthrough)
+ */
+ }
+
+ case GIMP_RUN_NONINTERACTIVE:
+ /* Make sure all the arguments are there */
+ if (nparams != (script->n_args + 1))
+ status = GIMP_PDB_CALLING_ERROR;
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ gchar *command;
+
+ command = script_fu_script_get_command_from_params (script,
+ params);
+
+ /* run the command through the interpreter */
+ if (! script_fu_run_command (command, &error))
+ {
+ status = GIMP_PDB_EXECUTION_ERROR;
+ *nreturn_vals = 2;
+ values[1].type = GIMP_PDB_STRING;
+ values[1].data.d_string = error->message;
+
+ error->message = NULL;
+ g_error_free (error);
+ }
+
+ g_free (command);
+ }
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ {
+ gchar *command;
+
+ /* First, try to collect the standard script arguments */
+ script_fu_script_collect_standard_args (script, nparams, params);
+
+ command = script_fu_script_get_command (script);
+
+ /* run the command through the interpreter */
+ if (! script_fu_run_command (command, &error))
+ {
+ status = GIMP_PDB_EXECUTION_ERROR;
+ *nreturn_vals = 2;
+ values[1].type = GIMP_PDB_STRING;
+ values[1].data.d_string = error->message;
+
+ error->message = NULL;
+ g_error_free (error);
+ }
+
+ g_free (command);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ values[0].data.d_status = status;
+}
+
+/* this is a GTraverseFunction */
+static gboolean
+script_fu_lookup_script (gpointer *foo G_GNUC_UNUSED,
+ GList *scripts,
+ gconstpointer *name)
+{
+ GList *list;
+
+ for (list = scripts; list; list = g_list_next (list))
+ {
+ SFScript *script = list->data;
+
+ if (strcmp (script->name, *name) == 0)
+ {
+ /* store the script in the name pointer and stop the traversal */
+ *name = script;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static SFScript *
+script_fu_find_script (const gchar *name)
+{
+ gconstpointer script = name;
+
+ g_tree_foreach (script_tree,
+ (GTraverseFunc) script_fu_lookup_script,
+ &script);
+
+ if (script == name)
+ return NULL;
+
+ return (SFScript *) script;
+}
+
+static gchar *
+script_fu_menu_map (const gchar *menu_path)
+{
+ /* for backward compatibility, we fiddle with some menu paths */
+ const struct
+ {
+ 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" }
+ };
+
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (mapping); i++)
+ {
+ if (g_str_has_prefix (menu_path, mapping[i].old))
+ {
+ const gchar *suffix = menu_path + strlen (mapping[i].old);
+
+ if (*suffix != '/')
+ continue;
+
+ return g_strconcat (mapping[i].new, suffix, NULL);
+ }
+ }
+
+ return NULL;
+}
+
+static gint
+script_fu_menu_compare (gconstpointer a,
+ gconstpointer b)
+{
+ const SFMenu *menu_a = a;
+ const SFMenu *menu_b = b;
+ gint retval = 0;
+
+ if (menu_a->menu_path && menu_b->menu_path)
+ {
+ retval = g_utf8_collate (menu_a->menu_path,
+ menu_b->menu_path);
+
+ if (retval == 0 &&
+ menu_a->script->menu_label && menu_b->script->menu_label)
+ {
+ retval = g_utf8_collate (menu_a->script->menu_label,
+ menu_b->script->menu_label);
+ }
+ }
+
+ return retval;
+}
diff --git a/plug-ins/script-fu/script-fu-scripts.h b/plug-ins/script-fu/script-fu-scripts.h
new file mode 100644
index 0000000..ef63870
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-scripts.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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_SCRIPTS_H__
+#define __SCRIPT_FU_SCRIPTS_H__
+
+
+void script_fu_find_scripts (GList *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/plug-ins/script-fu/script-fu-server.c b/plug-ins/script-fu/script-fu-server.c
new file mode 100644
index 0000000..74270bf
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-server.c
@@ -0,0 +1,1113 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <sys/types.h>
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#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>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0
+#endif
+#endif
+
+#include <glib/gstdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "script-fu-intl.h"
+
+#include "scheme-wrapper.h"
+#include "script-fu-server.h"
+
+#ifdef G_OS_WIN32
+#define CLOSESOCKET(fd) closesocket(fd)
+#else
+#define CLOSESOCKET(fd) close(fd)
+#endif
+
+#define COMMAND_HEADER 3
+#define RESPONSE_HEADER 4
+#define MAGIC 'G'
+
+#ifndef HAVE_DIFFTIME
+#define difftime(a,b) (((gdouble)(a)) - ((gdouble)(b)))
+#endif
+
+#ifndef NO_FD_SET
+# define SELECT_MASK fd_set
+#else
+# ifndef _AIX
+ typedef long fd_mask;
+# endif
+# if defined(_IBMR2)
+# define SELECT_MASK void
+# else
+# define SELECT_MASK int
+# endif
+#endif
+
+
+/* image information */
+
+/* Header format for incoming commands...
+ * bytes: 1 2 3
+ * MAGIC CMD_LEN_H CMD_LEN_L
+ */
+
+/* Header format for outgoing responses...
+ * bytes: 1 2 3 4
+ * MAGIC ERROR? RSP_LEN_H RSP_LEN_L
+ */
+
+#define MAGIC_BYTE 0
+
+#define CMD_LEN_H_BYTE 1
+#define CMD_LEN_L_BYTE 2
+
+#define ERROR_BYTE 1
+#define RSP_LEN_H_BYTE 2
+#define RSP_LEN_L_BYTE 3
+
+/*
+ * Local Types
+ */
+
+typedef struct
+{
+ gchar *command;
+ gint filedes;
+ gint request_no;
+} SFCommand;
+
+typedef struct
+{
+ GtkWidget *ip_entry;
+ GtkWidget *port_entry;
+ GtkWidget *log_entry;
+
+ gchar *listen_ip;
+ gint port;
+ gchar *logfile;
+
+ 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
+ */
+
+static void server_start (const gchar *listen_ip,
+ gint port,
+ const gchar *logfile);
+static gboolean execute_command (SFCommand *cmd);
+static gint read_from_client (gint filedes);
+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);
+
+static gboolean server_interface (void);
+static void response_callback (GtkWidget *widget,
+ gint response_id,
+ gpointer data);
+static void print_socket_api_error (const gchar *api_name);
+
+/*
+ * Local variables
+ */
+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;
+static FILE *server_log_file = NULL;
+static GHashTable *clients = NULL;
+static gboolean script_fu_done = FALSE;
+static gboolean server_mode = FALSE;
+
+static ServerInterface sint =
+{
+ NULL, /* port entry widget */
+ NULL, /* log entry widget */
+ NULL, /* ip entry widget */
+
+ NULL, /* ip to bind to */
+ 10008, /* default port number */
+ NULL, /* use stdout */
+
+ FALSE /* run */
+};
+
+/*
+ * Server interface functions
+ */
+
+void
+script_fu_server_quit (void)
+{
+ script_fu_done = TRUE;
+}
+
+gint
+script_fu_server_get_mode (void)
+{
+ return server_mode;
+}
+
+void
+script_fu_server_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;
+
+ ts_set_run_mode (run_mode);
+ ts_set_print_flag (1);
+
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ if (server_interface ())
+ {
+ server_mode = TRUE;
+
+ /* Start the server */
+ server_start (sint.listen_ip, sint.port, sint.logfile);
+ }
+ break;
+
+ case GIMP_RUN_NONINTERACTIVE:
+ /* Set server_mode to TRUE */
+ server_mode = TRUE;
+
+ /* Start the server */
+ server_start ((params[1].data.d_string &&
+ strlen (params[1].data.d_string)) ?
+ params[1].data.d_string : "127.0.0.1",
+ params[2].data.d_int32,
+ params[3].data.d_string);
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ status = GIMP_PDB_CALLING_ERROR;
+ g_warning ("Script-Fu server does not handle \"GIMP_RUN_WITH_LAST_VALS\"");
+
+ default:
+ break;
+ }
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = status;
+}
+
+static void
+script_fu_server_add_fd (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ FD_SET (GPOINTER_TO_INT (key), (SELECT_MASK *) data);
+}
+
+static gboolean
+script_fu_server_read_fd (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ gint fd = GPOINTER_TO_INT (key);
+
+ if (FD_ISSET (fd, (SELECT_MASK *) data))
+ {
+ if (read_from_client (fd) < 0)
+ {
+ GList *list;
+
+ server_log ("Server: disconnect from host %s.\n", (gchar *) value);
+
+ CLOSESOCKET (fd);
+
+ /* Invalidate the file descriptor for pending commands
+ from the disconnected client. */
+ for (list = command_queue; list; list = list->next)
+ {
+ SFCommand *cmd = (SFCommand *) command_queue->data;
+
+ if (cmd->filedes == fd)
+ cmd->filedes = -1;
+ }
+
+ return TRUE; /* remove this client from the hash table */
+ }
+ }
+
+ return FALSE;
+}
+
+void
+script_fu_server_listen (gint timeout)
+{
+ struct timeval tv;
+ struct timeval *tvp = NULL;
+ SELECT_MASK fds;
+ gint sockno;
+
+ /* Set time struct */
+ if (timeout)
+ {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000;
+ tvp = &tv;
+ }
+
+ FD_ZERO (&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
+ or timeout occurs. */
+
+ if (select (FD_SETSIZE, &fds, NULL, NULL, tvp) < 0)
+ {
+ print_socket_api_error ("select");
+ return;
+ }
+
+ /* Service the server sockets if any has input pending. */
+ for (sockno = 0; sockno < server_socks_used; sockno++)
+ {
+ sa_union client;
+ gchar clientname[NI_MAXHOST];
+
+ /* Connection request on original socket. */
+ socklen_t 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)
+ {
+ print_socket_api_error ("accept");
+ return;
+ }
+
+ /* Associate the client address with the socket */
+
+ /* 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",
+ clientname, portno);
+ }
+
+ /* Service the client sockets. */
+ g_hash_table_foreach_remove (clients, script_fu_server_read_fd, &fds);
+}
+
+static void
+server_progress_start (const gchar *message,
+ gboolean cancelable,
+ gpointer user_data)
+{
+ /* do nothing */
+}
+
+static void
+server_progress_end (gpointer user_data)
+{
+ /* do nothing */
+}
+
+static void
+server_progress_set_text (const gchar *message,
+ gpointer user_data)
+{
+ /* do nothing */
+}
+
+static void
+server_progress_set_value (gdouble percentage,
+ gpointer user_data)
+{
+ /* do nothing */
+}
+
+
+/*
+ * Suppress progress popups by installing progress handlers that do nothing.
+ */
+static const gchar *
+server_progress_install (void)
+{
+ GimpProgressVtable vtable = { 0, };
+
+ vtable.start = server_progress_start;
+ vtable.end = server_progress_end;
+ vtable.set_text = server_progress_set_text;
+ vtable.set_value = server_progress_set_value;
+
+ return gimp_progress_install_vtable (&vtable, NULL);
+}
+
+static void
+server_progress_uninstall (const gchar *progress)
+{
+ gimp_progress_uninstall (progress);
+}
+
+static void
+server_start (const gchar *listen_ip,
+ gint port,
+ const gchar *logfile)
+{
+ struct addrinfo *ai;
+ struct addrinfo *ai_curr;
+ struct addrinfo hints;
+ gint e;
+ gint sockno;
+ gchar *port_s;
+ const gchar *progress;
+
+ 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 (listen_ip, port_s, &hints, &ai);
+ g_free (port_s);
+
+ if (e != 0)
+ {
+ g_printerr ("getaddrinfo: %s\n", 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");
+ freeaddrinfo (ai);
+ return;
+ }
+ }
+
+ server_socks_used = sockno;
+
+ /* Setup up the server log file */
+ if (logfile && *logfile)
+ server_log_file = g_fopen (logfile, "a");
+ else
+ server_log_file = NULL;
+
+ if (! server_log_file)
+ server_log_file = stdout;
+
+ /* Set up the clientname hash table */
+ clients = g_hash_table_new_full (g_direct_hash, NULL,
+ NULL, (GDestroyNotify) g_free);
+
+ progress = server_progress_install ();
+
+ server_log ("Script-Fu server initialized and listening...\n");
+
+ /* Loop until the server is finished */
+ while (! script_fu_done)
+ {
+ script_fu_server_listen (0);
+
+ while (command_queue)
+ {
+ SFCommand *cmd = (SFCommand *) command_queue->data;
+
+ /* Process the command */
+ execute_command (cmd);
+
+ /* Remove the command from the list */
+ command_queue = g_list_remove (command_queue, cmd);
+ queue_length--;
+
+ /* Free the request */
+ g_free (cmd->command);
+ g_free (cmd);
+ }
+ }
+
+ server_progress_uninstall (progress);
+
+ freeaddrinfo (ai);
+ server_quit ();
+}
+
+static gboolean
+execute_command (SFCommand *cmd)
+{
+ guchar buffer[RESPONSE_HEADER];
+ GString *response;
+ time_t clocknow;
+ gboolean error;
+ gint i;
+ gdouble total_time;
+ GTimer *timer;
+
+ server_log ("Processing request #%d\n", cmd->request_no);
+ timer = g_timer_new ();
+
+ response = g_string_new (NULL);
+ ts_register_output_func (ts_gstring_output_func, response);
+
+ /* run the command */
+ if (ts_interpret_string (cmd->command) != 0)
+ {
+ error = TRUE;
+
+ server_log ("%s\n", response->str);
+ }
+ else
+ {
+ error = FALSE;
+
+ if (response->len == 0)
+ g_string_assign (response, ts_get_success_msg ());
+
+ total_time = g_timer_elapsed (timer, NULL);
+ time (&clocknow);
+ server_log ("Request #%d processed in %.3f seconds, finishing on %s",
+ cmd->request_no, total_time, ctime (&clocknow));
+ }
+ g_timer_destroy (timer);
+
+ buffer[MAGIC_BYTE] = MAGIC;
+ buffer[ERROR_BYTE] = error ? TRUE : FALSE;
+ buffer[RSP_LEN_H_BYTE] = (guchar) (response->len >> 8);
+ buffer[RSP_LEN_L_BYTE] = (guchar) (response->len & 0xFF);
+
+ /* Write the response to the client */
+ for (i = 0; i < RESPONSE_HEADER; i++)
+ if (cmd->filedes > 0 && send (cmd->filedes, (const void *) (buffer + i), 1, 0) < 0)
+ {
+ /* Write error */
+ print_socket_api_error ("send");
+ return FALSE;
+ }
+
+ for (i = 0; i < response->len; i++)
+ if (cmd->filedes > 0 && send (cmd->filedes, response->str + i, 1, 0) < 0)
+ {
+ /* Write error */
+ print_socket_api_error ("send");
+ return FALSE;
+ }
+
+ g_string_free (response, TRUE);
+
+ return FALSE;
+}
+
+static gint
+read_from_client (gint filedes)
+{
+ SFCommand *cmd;
+ guchar buffer[COMMAND_HEADER];
+ gchar *command;
+ gchar *clientaddr;
+ time_t clock;
+ gint command_len;
+ gint nbytes;
+ gint i;
+
+ for (i = 0; i < COMMAND_HEADER;)
+ {
+ nbytes = recv (filedes, (void *) (buffer + i), COMMAND_HEADER - i, 0);
+
+ if (nbytes < 0)
+ {
+#ifndef G_OS_WIN32
+ if (errno == EINTR)
+ continue;
+#endif
+ server_log ("Error reading command header.\n");
+ return -1;
+ }
+
+ if (nbytes == 0)
+ return -1; /* EOF */
+
+ i += nbytes;
+ }
+
+ if (buffer[MAGIC_BYTE] != MAGIC)
+ {
+ server_log ("Error in script-fu command transmission.\n");
+ return -1;
+ }
+
+ command_len = (buffer [CMD_LEN_H_BYTE] << 8) | buffer [CMD_LEN_L_BYTE];
+ command = g_new (gchar, command_len + 1);
+
+ for (i = 0; i < command_len;)
+ {
+ nbytes = recv (filedes, command + i, command_len - i, 0);
+
+ if (nbytes <= 0)
+ {
+#ifndef G_OS_WIN32
+ if (nbytes < 0 && errno == EINTR)
+ continue;
+#endif
+ server_log ("Error reading command. Read %d out of %d bytes.\n",
+ i, command_len);
+ g_free (command);
+ return -1;
+ }
+
+ i += nbytes;
+ }
+
+ command[command_len] = '\0';
+ cmd = g_new (SFCommand, 1);
+
+ cmd->filedes = filedes;
+ cmd->command = command;
+ cmd->request_no = request_no ++;
+
+ /* Add the command to the queue */
+ command_queue = g_list_append (command_queue, cmd);
+ queue_length ++;
+
+ /* Get the client address from the address/socket table */
+ clientaddr = g_hash_table_lookup (clients, GINT_TO_POINTER (cmd->filedes));
+ time (&clock);
+ server_log ("Received request #%d from IP address %s: %s on %s,"
+ "[Request queue length: %d]",
+ cmd->request_no,
+ clientaddr ? clientaddr : "<invalid>",
+ cmd->command, ctime (&clock), queue_length);
+
+ return 0;
+}
+
+static gint
+make_socket (const struct addrinfo *ai)
+{
+ gint sock;
+ gint v = 1;
+
+ /* Win32 needs the winsock library initialized. */
+#ifdef G_OS_WIN32
+ static gboolean winsock_initialized = FALSE;
+
+ if (! winsock_initialized)
+ {
+ WORD wVersionRequested = MAKEWORD (2, 2);
+ WSADATA wsaData;
+
+ if (WSAStartup (wVersionRequested, &wsaData) == 0)
+ {
+ winsock_initialized = TRUE;
+ }
+ else
+ {
+ print_socket_api_error ("WSAStartup");
+ gimp_quit ();
+ }
+ }
+#endif
+
+ /* Create the socket. */
+ sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock < 0)
+ {
+ print_socket_api_error ("socket");
+ gimp_quit ();
+ }
+
+ setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &v, sizeof(v));
+
+#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, (const void *) &v, sizeof(v)) < 0)
+ {
+ print_socket_api_error ("setsockopt");
+ gimp_quit();
+ }
+ }
+#endif
+
+ if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0)
+ {
+ print_socket_api_error ("bind");
+ gimp_quit ();
+ }
+
+ return sock;
+}
+
+static void
+server_log (const gchar *format,
+ ...)
+{
+ va_list args;
+ gchar *buf;
+
+ va_start (args, format);
+ buf = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ fputs (buf, server_log_file);
+ g_free (buf);
+
+ if (server_log_file != stdout)
+ fflush (server_log_file);
+}
+
+static void
+script_fu_server_shutdown_fd (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ shutdown (GPOINTER_TO_INT (key), 2);
+}
+
+static void
+server_quit (void)
+{
+ gint sockno;
+
+ for (sockno = 0; sockno < server_socks_used; sockno++)
+ {
+ CLOSESOCKET (server_socks[sockno]);
+ }
+
+ if (clients)
+ {
+ g_hash_table_foreach (clients, script_fu_server_shutdown_fd, NULL);
+ g_hash_table_destroy (clients);
+ clients = NULL;
+ }
+
+ while (command_queue)
+ {
+ SFCommand *cmd = command_queue->data;
+
+ g_free (cmd->command);
+ g_free (cmd);
+ }
+
+ g_list_free (command_queue);
+ command_queue = NULL;
+ queue_length = 0;
+
+ /* Close the server log file */
+ if (server_log_file != stdout)
+ fclose (server_log_file);
+
+ server_log_file = NULL;
+}
+
+static gboolean
+server_interface (void)
+{
+ GtkWidget *dlg;
+ GtkWidget *main_vbox;
+ GtkWidget *table;
+ GtkWidget *hbox;
+ GtkWidget *image;
+ GtkWidget *label;
+
+ INIT_I18N();
+
+ gimp_ui_init ("script-fu", FALSE);
+
+ dlg = gimp_dialog_new (_("Script-Fu Server Options"), "gimp-script-fu",
+ NULL, 0,
+ gimp_standard_help_func, "plug-in-script-fu-server",
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Start Server"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ g_signal_connect (dlg, "response",
+ G_CALLBACK (response_callback),
+ NULL);
+ g_signal_connect (dlg, "destroy",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
+ main_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (main_vbox);
+
+ /* The table to hold port, logfile and listen-to entries */
+ table = gtk_table_new (3, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+ gtk_widget_show (table);
+
+ /* The server ip to listen to */
+ sint.ip_entry = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (sint.ip_entry), "127.0.0.1");
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("Listen on IP:"), 0.0, 0.5,
+ sint.ip_entry, 1, FALSE);
+
+ /* The server port */
+ sint.port_entry = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (sint.port_entry), "10008");
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("Server port:"), 0.0, 0.5,
+ sint.port_entry, 1, FALSE);
+
+ /* The server logfile */
+ sint.log_entry = gtk_entry_new ();
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
+ _("Server logfile:"), 0.0, 0.5,
+ sint.log_entry, 1, FALSE);
+
+ /* Warning */
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ image = gtk_image_new_from_icon_name (GIMP_ICON_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0);
+ gtk_widget_show (image);
+
+ label = gtk_label_new (_("Listening on an IP address other than "
+ "127.0.0.1 (especially 0.0.0.0) can allow "
+ "attackers to remotely execute arbitrary code "
+ "on this machine."));
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
+ -1);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ gtk_widget_show (dlg);
+
+ gtk_main ();
+
+ return sint.run;
+}
+
+static void
+response_callback (GtkWidget *widget,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ g_free (sint.logfile);
+ g_free (sint.listen_ip);
+
+ sint.port = atoi (gtk_entry_get_text (GTK_ENTRY (sint.port_entry)));
+ sint.logfile = g_strdup (gtk_entry_get_text (GTK_ENTRY (sint.log_entry)));
+ sint.listen_ip = g_strdup (gtk_entry_get_text (GTK_ENTRY (sint.ip_entry)));
+ sint.run = TRUE;
+ }
+
+ gtk_widget_destroy (widget);
+}
+
+static void
+print_socket_api_error (const gchar *api_name)
+{
+#ifdef G_OS_WIN32
+ /* Yes, this functionality really belongs to GLib. */
+ const gchar *emsg;
+ gchar unk[100];
+ int number = WSAGetLastError ();
+
+ switch (number)
+ {
+ case WSAEINTR:
+ emsg = "Interrupted function call";
+ break;
+ case WSAEACCES:
+ emsg = "Permission denied";
+ break;
+ case WSAEFAULT:
+ emsg = "Bad address";
+ break;
+ case WSAEINVAL:
+ emsg = "Invalid argument";
+ break;
+ case WSAEMFILE:
+ emsg = "Too many open sockets";
+ break;
+ case WSAEWOULDBLOCK:
+ emsg = "Resource temporarily unavailable";
+ break;
+ case WSAEINPROGRESS:
+ emsg = "Operation now in progress";
+ break;
+ case WSAEALREADY:
+ emsg = "Operation already in progress";
+ break;
+ case WSAENOTSOCK:
+ emsg = "Socket operation on nonsocket";
+ break;
+ case WSAEDESTADDRREQ:
+ emsg = "Destination address required";
+ break;
+ case WSAEMSGSIZE:
+ emsg = "Message too long";
+ break;
+ case WSAEPROTOTYPE:
+ emsg = "Protocol wrong type for socket";
+ break;
+ case WSAENOPROTOOPT:
+ emsg = "Bad protocol option";
+ break;
+ case WSAEPROTONOSUPPORT:
+ emsg = "Protocol not supported";
+ break;
+ case WSAESOCKTNOSUPPORT:
+ emsg = "Socket type not supported";
+ break;
+ case WSAEOPNOTSUPP:
+ emsg = "Operation not supported on transport endpoint";
+ break;
+ case WSAEPFNOSUPPORT:
+ emsg = "Protocol family not supported";
+ break;
+ case WSAEAFNOSUPPORT:
+ emsg = "Address family not supported by protocol family";
+ break;
+ case WSAEADDRINUSE:
+ emsg = "Address already in use";
+ break;
+ case WSAEADDRNOTAVAIL:
+ emsg = "Address not available";
+ break;
+ case WSAENETDOWN:
+ emsg = "Network interface is not configured";
+ break;
+ case WSAENETUNREACH:
+ emsg = "Network is unreachable";
+ break;
+ case WSAENETRESET:
+ emsg = "Network dropped connection on reset";
+ break;
+ case WSAECONNABORTED:
+ emsg = "Software caused connection abort";
+ break;
+ case WSAECONNRESET:
+ emsg = "Connection reset by peer";
+ break;
+ case WSAENOBUFS:
+ emsg = "No buffer space available";
+ break;
+ case WSAEISCONN:
+ emsg = "Socket is already connected";
+ break;
+ case WSAENOTCONN:
+ emsg = "Socket is not connected";
+ break;
+ case WSAESHUTDOWN:
+ emsg = "Can't send after socket shutdown";
+ break;
+ case WSAETIMEDOUT:
+ emsg = "Connection timed out";
+ break;
+ case WSAECONNREFUSED:
+ emsg = "Connection refused";
+ break;
+ case WSAEHOSTDOWN:
+ emsg = "Host is down";
+ break;
+ case WSAEHOSTUNREACH:
+ emsg = "Host is unreachable";
+ break;
+ case WSAEPROCLIM:
+ emsg = "Too many processes";
+ break;
+ case WSASYSNOTREADY:
+ emsg = "Network subsystem is unavailable";
+ break;
+ case WSAVERNOTSUPPORTED:
+ emsg = "Winsock.dll version out of range";
+ break;
+ case WSANOTINITIALISED:
+ emsg = "Successful WSAStartup not yet performed";
+ break;
+ case WSAEDISCON:
+ emsg = "Graceful shutdown in progress";
+ break;
+ case WSATYPE_NOT_FOUND:
+ emsg = "Class type not found";
+ break;
+ case WSAHOST_NOT_FOUND:
+ emsg = "Host not found";
+ break;
+ case WSATRY_AGAIN:
+ emsg = "Nonauthoritative host not found";
+ break;
+ case WSANO_RECOVERY:
+ emsg = "This is a nonrecoverable error";
+ break;
+ case WSANO_DATA:
+ emsg = "Valid name, no data record of requested type";
+ break;
+ case WSA_INVALID_HANDLE:
+ emsg = "Specified event object handle is invalid";
+ break;
+ case WSA_INVALID_PARAMETER:
+ emsg = "One or more parameters are invalid";
+ break;
+ case WSA_IO_INCOMPLETE:
+ emsg = "Overlapped I/O event object not in signaled state";
+ break;
+ case WSA_NOT_ENOUGH_MEMORY:
+ emsg = "Insufficient memory available";
+ break;
+ case WSA_OPERATION_ABORTED:
+ emsg = "Overlapped operation aborted";
+ break;
+ case WSAEINVALIDPROCTABLE:
+ emsg = "Invalid procedure table from service provider";
+ break;
+ case WSAEINVALIDPROVIDER:
+ emsg = "Invalid service provider version number";
+ break;
+ case WSAEPROVIDERFAILEDINIT:
+ emsg = "Unable to initialize a service provider";
+ break;
+ case WSASYSCALLFAILURE:
+ emsg = "System call failure";
+ break;
+ default:
+ sprintf (unk, "Unknown WinSock error %d", number);
+ emsg = unk;
+ break;
+ }
+
+ g_printerr ("%s failed: %s\n", api_name, emsg);
+#else
+ perror (api_name);
+#endif
+}
diff --git a/plug-ins/script-fu/script-fu-server.h b/plug-ins/script-fu/script-fu-server.h
new file mode 100644
index 0000000..96b88ee
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-server.h
@@ -0,0 +1,32 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_SERVER_H__
+#define __SCRIPT_FU_SERVER_H__
+
+
+void script_fu_server_run (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+void script_fu_server_listen (gint timeout);
+gint script_fu_server_get_mode (void);
+void script_fu_server_quit (void);
+
+
+#endif /* __SCRIPT_FU_SERVER__ */
diff --git a/plug-ins/script-fu/script-fu-text-console.c b/plug-ins/script-fu/script-fu-text-console.c
new file mode 100644
index 0000000..94c8d7c
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-text-console.c
@@ -0,0 +1,60 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "libgimp/gimp.h"
+
+#include "scheme-wrapper.h"
+#include "script-fu-text-console.h"
+
+#include "script-fu-intl.h"
+
+void
+script_fu_text_console_run (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[1];
+
+ /* Enable Script-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 ();
+
+ 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;
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+}
diff --git a/plug-ins/script-fu/script-fu-text-console.h b/plug-ins/script-fu/script-fu-text-console.h
new file mode 100644
index 0000000..83c9860
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-text-console.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 <https://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);
+
+
+#endif /* __SCRIPT_FU_TEXT_CONSOLE_H__ */
diff --git a/plug-ins/script-fu/script-fu-types.h b/plug-ins/script-fu/script-fu-types.h
new file mode 100644
index 0000000..f0231b5
--- /dev/null
+++ b/plug-ins/script-fu/script-fu-types.h
@@ -0,0 +1,107 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCRIPT_FU_TYPES_H__
+#define __SCRIPT_FU_TYPES_H__
+
+
+#include "script-fu-enums.h"
+
+
+typedef struct
+{
+ GtkAdjustment *adj;
+ gdouble value;
+ gdouble lower;
+ gdouble upper;
+ gdouble step;
+ gdouble page;
+ gint digits;
+ SFAdjustmentType type;
+} SFAdjustment;
+
+typedef struct
+{
+ gchar *filename;
+} SFFilename;
+
+typedef struct
+{
+ gchar *name;
+ gdouble opacity;
+ gint spacing;
+ GimpLayerMode paint_mode;
+} SFBrush;
+
+typedef struct
+{
+ GSList *list;
+ gint history;
+} SFOption;
+
+typedef struct
+{
+ gchar *type_name;
+ gint history;
+} SFEnum;
+
+typedef union
+{
+ gint32 sfa_image;
+ gint32 sfa_drawable;
+ gint32 sfa_layer;
+ gint32 sfa_channel;
+ gint32 sfa_vectors;
+ gint32 sfa_display;
+ GimpRGB sfa_color;
+ gint32 sfa_toggle;
+ gchar *sfa_value;
+ SFAdjustment sfa_adjustment;
+ SFFilename sfa_file;
+ gchar *sfa_font;
+ gchar *sfa_gradient;
+ gchar *sfa_palette;
+ gchar *sfa_pattern;
+ SFBrush sfa_brush;
+ SFOption sfa_option;
+ SFEnum sfa_enum;
+} SFArgValue;
+
+typedef struct
+{
+ 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;
+
+
+#endif /* __SCRIPT_FU_TYPES__ */
diff --git a/plug-ins/script-fu/script-fu-utils.c b/plug-ins/script-fu/script-fu-utils.c
new file mode 100644
index 0000000..3e068cc
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "script-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/plug-ins/script-fu/script-fu-utils.h b/plug-ins/script-fu/script-fu-utils.h
new file mode 100644
index 0000000..a62a226
--- /dev/null
+++ b/plug-ins/script-fu/script-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 <https://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/plug-ins/script-fu/script-fu.c b/plug-ins/script-fu/script-fu.c
new file mode 100644
index 0000000..558e15a
--- /dev/null
+++ b/plug-ins/script-fu/script-fu.c
@@ -0,0 +1,385 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "tinyscheme/scheme.h"
+
+#include "script-fu-types.h"
+
+#include "script-fu-console.h"
+#include "script-fu-eval.h"
+#include "script-fu-interface.h"
+#include "script-fu-scripts.h"
+#include "script-fu-server.h"
+#include "script-fu-text-console.h"
+
+#include "scheme-wrapper.h"
+
+#include "script-fu-intl.h"
+
+
+/* Declare local functions. */
+
+static void script_fu_query (void);
+static void script_fu_run (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+static GList * script_fu_search_path (void);
+static void script_fu_extension_init (void);
+static void script_fu_refresh_proc (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ script_fu_query, /* query_proc */
+ script_fu_run /* run_proc */
+};
+
+
+MAIN ()
+
+
+static void
+script_fu_query (void)
+{
+ static const GimpParamDef console_args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0) }" }
+ };
+
+ static const GimpParamDef textconsole_args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0) }" }
+ };
+
+ static const GimpParamDef eval_args[] =
+ {
+ { 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", "The run mode { RUN-NONINTERACTIVE (1) }" },
+ { GIMP_PDB_STRING, "ip", "The ip on which to listen for requests" },
+ { GIMP_PDB_INT32, "port", "The port on which to listen for requests" },
+ { GIMP_PDB_STRING, "logfile", "The file to log server activity to" }
+ };
+
+ gimp_plugin_domain_register (GETTEXT_PACKAGE "-script-fu", NULL);
+
+ gimp_install_procedure ("extension-script-fu",
+ "A scheme interpreter for scripting GIMP operations",
+ "More help here later",
+ "Spencer Kimball & Peter Mattis",
+ "Spencer Kimball & Peter Mattis",
+ "1997",
+ NULL,
+ NULL,
+ GIMP_EXTENSION,
+ 0, 0, NULL, NULL);
+
+ gimp_install_procedure ("plug-in-script-fu-console",
+ N_("Interactive console for Script-Fu development"),
+ "Provides an interface which allows interactive "
+ "scheme development.",
+ "Spencer Kimball & Peter Mattis",
+ "Spencer Kimball & Peter Mattis",
+ "1997",
+ N_("_Console"),
+ NULL,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (console_args), 0,
+ console_args, NULL);
+
+ gimp_plugin_menu_register ("plug-in-script-fu-console",
+ "<Image>/Filters/Languages/Script-Fu");
+
+ gimp_install_procedure ("plug-in-script-fu-text-console",
+ "Provides a text console mode for script-fu "
+ "development",
+ "Provides an interface which allows interactive "
+ "scheme development.",
+ "Spencer Kimball & Peter Mattis",
+ "Spencer Kimball & Peter Mattis",
+ "1997",
+ NULL,
+ NULL,
+ GIMP_PLUGIN,
+ 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. "
+ "NOTE that for security reasons this procedure's "
+ "API was changed in an incompatible way since "
+ "GIMP 2.8.12. You now have to pass the IP to listen "
+ "on as first parameter. Calling this procedure with "
+ "the old API will fail on purpose.",
+ "Spencer Kimball & Peter Mattis",
+ "Spencer Kimball & Peter Mattis",
+ "1997",
+ N_("_Start Server..."),
+ NULL,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (server_args), 0,
+ server_args, NULL);
+
+ gimp_plugin_menu_register ("plug-in-script-fu-server",
+ "<Image>/Filters/Languages/Script-Fu");
+
+ gimp_install_procedure ("plug-in-script-fu-eval",
+ "Evaluate scheme code",
+ "Evaluate the code under the scheme interpreter "
+ "(primarily for batch mode)",
+ "Manish Singh",
+ "Manish Singh",
+ "1998",
+ NULL,
+ NULL,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (eval_args), 0,
+ eval_args, NULL);
+}
+
+static void
+script_fu_run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ GList *path;
+
+ INIT_I18N();
+
+ path = script_fu_search_path ();
+
+ /* 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)
+ {
+ /* Setup auxiliary temporary procedures for the base extension */
+ script_fu_extension_init ();
+
+ /* Init the interpreter and register scripts */
+ tinyscheme_init (path, TRUE);
+ }
+ else
+ {
+ /* Init the interpreter */
+ tinyscheme_init (path, FALSE);
+ }
+
+ if (param != NULL)
+ ts_set_run_mode ((GimpRunMode) param[0].data.d_int32);
+
+ /* Load all of the available scripts */
+ script_fu_find_scripts (path);
+
+ g_list_free_full (path, (GDestroyNotify) g_object_unref);
+
+ if (strcmp (name, "extension-script-fu") == 0)
+ {
+ /*
+ * The main script-fu extension.
+ */
+
+ static GimpParam values[1];
+
+ /* Acknowledge that the extension is properly initialized */
+ gimp_extension_ack ();
+
+ /* Go into an endless loop */
+ while (TRUE)
+ gimp_extension_process (0);
+
+ /* Set return values; pointless because we never get out of the loop */
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ 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)
+ {
+ /*
+ * The script-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)
+ {
+ /*
+ * The script-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)
+ {
+ /*
+ * The script-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)
+ {
+ /*
+ * A non-interactive "console" (for batch mode)
+ */
+
+ script_fu_eval_run (name, nparams, param,
+ nreturn_vals, return_vals);
+ }
+}
+
+static GList *
+script_fu_search_path (void)
+{
+ gchar *path_str;
+ GList *path = NULL;
+
+ path_str = gimp_gimprc_query ("script-fu-path");
+
+ if (path_str)
+ {
+ GError *error = NULL;
+
+ path = gimp_config_path_expand_to_files (path_str, &error);
+ g_free (path_str);
+
+ if (! path)
+ {
+ g_warning ("Can't convert script-fu-path to filesystem encoding: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ return path;
+}
+
+static void
+script_fu_extension_init (void)
+{
+ static const GimpParamDef args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "[Interactive], non-interactive" }
+ };
+
+ 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 ("<Image>/Filters/Languages",
+ N_("_Script-Fu"));
+ gimp_plugin_menu_branch_register ("<Image>/Filters/Languages/Script-Fu",
+ N_("_Test"));
+
+ gimp_plugin_menu_branch_register ("<Image>/File/Create",
+ N_("_Buttons"));
+ gimp_plugin_menu_branch_register ("<Image>/File/Create",
+ N_("_Logos"));
+ gimp_plugin_menu_branch_register ("<Image>/File/Create",
+ N_("_Patterns"));
+
+ gimp_plugin_menu_branch_register ("<Image>/File/Create",
+ N_("_Web Page Themes"));
+ gimp_plugin_menu_branch_register ("<Image>/File/Create/Web Page Themes",
+ N_("_Alien Glow"));
+ gimp_plugin_menu_branch_register ("<Image>/File/Create/Web Page Themes",
+ N_("_Beveled Pattern"));
+ 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_install_temp_proc ("script-fu-refresh",
+ N_("Re-read all available Script-Fu scripts"),
+ "Re-read all available Script-Fu scripts",
+ "Spencer Kimball & Peter Mattis",
+ "Spencer Kimball & Peter Mattis",
+ "1997",
+ N_("_Refresh Scripts"),
+ NULL,
+ GIMP_TEMPORARY,
+ G_N_ELEMENTS (args), 0,
+ args, NULL,
+ script_fu_refresh_proc);
+
+ gimp_plugin_menu_register ("script-fu-refresh",
+ "<Image>/Filters/Languages/Script-Fu");
+}
+
+static void
+script_fu_refresh_proc (const gchar *name,
+ gint nparams,
+ const GimpParam *params,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[1];
+ GimpPDBStatusType status;
+
+ 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."));
+
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+ else
+ {
+ /* Reload all of the available scripts */
+ GList *path = script_fu_search_path ();
+
+ script_fu_find_scripts (path);
+
+ g_list_free_full (path, (GDestroyNotify) g_object_unref);
+
+ status = GIMP_PDB_SUCCESS;
+ }
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = status;
+}
diff --git a/plug-ins/script-fu/scripts/Makefile.am b/plug-ins/script-fu/scripts/Makefile.am
new file mode 100644
index 0000000..4cce60d
--- /dev/null
+++ b/plug-ins/script-fu/scripts/Makefile.am
@@ -0,0 +1,70 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = images
+
+scriptdatadir = $(gimpdatadir)/scripts
+
+scripts = \
+ script-fu.init \
+ script-fu-compat.init \
+ plug-in-compat.init \
+ add-bevel.scm \
+ addborder.scm \
+ blend-anim.scm \
+ burn-in-anim.scm \
+ carve-it.scm \
+ chrome-it.scm \
+ circuit.scm \
+ clothify.scm \
+ coffee.scm \
+ copy-visible.scm \
+ difference-clouds.scm \
+ distress-selection.scm \
+ drop-shadow.scm \
+ erase-rows.scm \
+ font-map.scm \
+ fuzzyborder.scm \
+ gimp-online.scm \
+ gradient-example.scm \
+ grid-system.scm \
+ guides-from-selection.scm \
+ guides-new.scm \
+ guides-new-percent.scm \
+ guides-remove-all.scm \
+ lava.scm \
+ line-nova.scm \
+ mkbrush.scm \
+ old-photo.scm \
+ palette-export.scm \
+ paste-as-brush.scm \
+ paste-as-pattern.scm \
+ perspective-shadow.scm \
+ predator.scm \
+ reverse-layers.scm \
+ ripply-anim.scm \
+ round-corners.scm \
+ script-fu-set-cmap.scm \
+ script-fu-util.scm \
+ select-to-brush.scm \
+ select-to-image.scm \
+ select-to-pattern.scm \
+ selection-round.scm \
+ slide.scm \
+ spinning-globe.scm \
+ spyrogimp.scm \
+ tileblur.scm \
+ unsharp-mask.scm \
+ waves-anim.scm \
+ weave.scm \
+ xach-effect.scm
+
+test_scripts = \
+ contactsheet.scm \
+ test-sphere.scm \
+ ts-helloworld.scm
+
+
+scriptdata_DATA = $(scripts)
+
+
+EXTRA_DIST = $(scripts) $(test_scripts)
diff --git a/plug-ins/script-fu/scripts/Makefile.in b/plug-ins/script-fu/scripts/Makefile.in
new file mode 100644
index 0000000..e4554bf
--- /dev/null
+++ b/plug-ins/script-fu/scripts/Makefile.in
@@ -0,0 +1,1044 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plug-ins/script-fu/scripts
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(scriptdatadir)"
+DATA = $(scriptdata_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = images
+scriptdatadir = $(gimpdatadir)/scripts
+scripts = \
+ script-fu.init \
+ script-fu-compat.init \
+ plug-in-compat.init \
+ add-bevel.scm \
+ addborder.scm \
+ blend-anim.scm \
+ burn-in-anim.scm \
+ carve-it.scm \
+ chrome-it.scm \
+ circuit.scm \
+ clothify.scm \
+ coffee.scm \
+ copy-visible.scm \
+ difference-clouds.scm \
+ distress-selection.scm \
+ drop-shadow.scm \
+ erase-rows.scm \
+ font-map.scm \
+ fuzzyborder.scm \
+ gimp-online.scm \
+ gradient-example.scm \
+ grid-system.scm \
+ guides-from-selection.scm \
+ guides-new.scm \
+ guides-new-percent.scm \
+ guides-remove-all.scm \
+ lava.scm \
+ line-nova.scm \
+ mkbrush.scm \
+ old-photo.scm \
+ palette-export.scm \
+ paste-as-brush.scm \
+ paste-as-pattern.scm \
+ perspective-shadow.scm \
+ predator.scm \
+ reverse-layers.scm \
+ ripply-anim.scm \
+ round-corners.scm \
+ script-fu-set-cmap.scm \
+ script-fu-util.scm \
+ select-to-brush.scm \
+ select-to-image.scm \
+ select-to-pattern.scm \
+ selection-round.scm \
+ slide.scm \
+ spinning-globe.scm \
+ spyrogimp.scm \
+ tileblur.scm \
+ unsharp-mask.scm \
+ waves-anim.scm \
+ weave.scm \
+ xach-effect.scm
+
+test_scripts = \
+ contactsheet.scm \
+ test-sphere.scm \
+ ts-helloworld.scm
+
+scriptdata_DATA = $(scripts)
+EXTRA_DIST = $(scripts) $(test_scripts)
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/script-fu/scripts/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/script-fu/scripts/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-scriptdataDATA: $(scriptdata_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(scriptdata_DATA)'; test -n "$(scriptdatadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(scriptdatadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(scriptdatadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(scriptdatadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(scriptdatadir)" || exit $$?; \
+ done
+
+uninstall-scriptdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(scriptdata_DATA)'; test -n "$(scriptdatadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(scriptdatadir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(scriptdatadir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-scriptdataDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-scriptdataDATA
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-scriptdataDATA install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-scriptdataDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/script-fu/scripts/add-bevel.scm b/plug-ins/script-fu/scripts/add-bevel.scm
new file mode 100644
index 0000000..6e0f951
--- /dev/null
+++ b/plug-ins/script-fu/scripts/add-bevel.scm
@@ -0,0 +1,202 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; add-bevel.scm version 1.04
+; Time-stamp: <2004-02-09 17:07:06 simon>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Copyright (C) 1997 Andrew Donkin (ard@cs.waikato.ac.nz)
+; Contains code from add-shadow.scm by Sven Neumann
+; (neumanns@uni-duesseldorf.de) (thanks Sven).
+;
+; Adds a bevel to an image. See http://www.cs.waikato.ac.nz/~ard/gimp/
+;
+; If there is a selection, it is bevelled.
+; Otherwise if there is an alpha channel, the selection is taken from it
+; and bevelled.
+; Otherwise the part of the layer inside the image boundaries is bevelled.
+;
+; The selection is set on exit, so Select->Invert then Edit->Clear will
+; leave a cut-out. Then use Sven's add-shadow for that
+; floating-bumpmapped-texture cliche.
+
+;
+; 1.01: now works on offset layers.
+; 1.02: has crop-pixel-border option to trim one pixel off each edge of the
+; bevelled image. Bumpmapping leaves edge pixels unchanged, which
+; looks bad. Oddly, this is not apparent in GIMP - you have to
+; save the image and load it into another viewer. First noticed in
+; Nutscrape.
+; Changed path (removed "filters/").
+; 1.03: adds one-pixel border before bumpmapping, and removes it after.
+; Got rid of the crop-pixel-border option (no longer reqd).
+; 1.04: Fixed undo handling, ensure that bumpmap is big enough,
+; (instead of resizing the image). Removed references to outdated
+; bumpmap plugin. (Simon)
+; 1.05 When there is no selection, bevel the whole layer instead of the
+; whole image (which was broken in the first place).
+; Also fixed some bugs with setting the selection when there is no
+; initial selection. (Barak Itkin)
+;
+
+(define (script-fu-add-bevel img
+ drawable
+ thickness
+ work-on-copy
+ keep-bump-layer)
+
+ (let* (
+ (index 1)
+ (greyness 0)
+ (thickness (abs thickness))
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image (if (= work-on-copy TRUE) (car (gimp-image-duplicate img)) img))
+ (pic-layer (car (gimp-image-get-active-drawable image)))
+ (offsets (gimp-drawable-offsets pic-layer))
+ (width (car (gimp-drawable-width pic-layer)))
+ (height (car (gimp-drawable-height pic-layer)))
+
+ ; Bumpmap has a one pixel border on each side
+ (bump-layer (car (gimp-layer-new image
+ (+ width 2)
+ (+ height 2)
+ RGB-IMAGE
+ _"Bumpmap"
+ 100
+ LAYER-MODE-NORMAL)))
+
+ (selection-exists (car (gimp-selection-bounds image)))
+ (selection 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ ; disable undo on copy, start group otherwise
+ (if (= work-on-copy TRUE)
+ (gimp-image-undo-disable image)
+ (gimp-image-undo-group-start image)
+ )
+
+ (gimp-image-insert-layer image bump-layer 0 1)
+
+ ; If the layer we're bevelling is offset from the image's origin, we
+ ; have to do the same to the bumpmap
+ (gimp-layer-set-offsets bump-layer (- (car offsets) 1)
+ (- (cadr offsets) 1))
+
+ ;------------------------------------------------------------
+ ;
+ ; Set the selection to the area we want to bevel.
+ ;
+ (if (= selection-exists 0)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE pic-layer)
+ )
+
+ ; Store it for later.
+ (set! selection (car (gimp-selection-save image)))
+ ; Try to lose the jaggies
+ (gimp-selection-feather image 2)
+
+ ;------------------------------------------------------------
+ ;
+ ; Initialise our bumpmap
+ ;
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-fill bump-layer FILL-BACKGROUND)
+
+ (while (and (< index thickness)
+ (= (car (gimp-selection-is-empty image)) FALSE)
+ )
+ (set! greyness (/ (* index 255) thickness))
+ (gimp-context-set-background (list greyness greyness greyness))
+ ;(gimp-selection-feather image 1) ;Stop the slopey jaggies?
+ (gimp-drawable-edit-fill bump-layer FILL-BACKGROUND)
+ (gimp-selection-shrink image 1)
+ (set! index (+ index 1))
+ )
+ ; Now the white interior
+ (if (= (car (gimp-selection-is-empty image)) FALSE)
+ (begin
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill bump-layer FILL-BACKGROUND)
+ )
+ )
+
+ ;------------------------------------------------------------
+ ;
+ ; Do the bump.
+ ;
+ (gimp-selection-none image)
+
+ ; To further lessen jaggies?
+ ;(plug-in-gauss-rle RUN-NONINTERACTIVE image bump-layer thickness TRUE TRUE)
+
+
+ ;
+ ; BUMPMAP INVOCATION:
+ ;
+ (plug-in-bump-map RUN-NONINTERACTIVE image pic-layer bump-layer 125 45 3 0 0 0 0 TRUE FALSE 1)
+
+ ;------------------------------------------------------------
+ ;
+ ; Restore things
+ ;
+ (if (= selection-exists 0)
+ (gimp-selection-none image) ; No selection to start with
+ (gimp-image-select-item image CHANNEL-OP-REPLACE selection)
+ )
+ ; If they started with a selection, they can Select->Invert then
+ ; Edit->Clear for a cutout.
+
+ ; clean up
+ (gimp-image-remove-channel image selection)
+ (if (= keep-bump-layer TRUE)
+ (gimp-item-set-visible bump-layer 0)
+ (gimp-image-remove-layer image bump-layer)
+ )
+
+ (gimp-image-set-active-layer image pic-layer)
+
+ ; enable undo / end undo group
+ (if (= work-on-copy TRUE)
+ (begin
+ (gimp-display-new image)
+ (gimp-image-undo-enable image)
+ )
+ (gimp-image-undo-group-end image)
+ )
+
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-add-bevel"
+ _"Add B_evel..."
+ _"Add a beveled border to an image"
+ "Andrew Donkin <ard@cs.waikato.ac.nz>"
+ "Andrew Donkin"
+ "1997/11/06"
+ "RGB*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Thickness" '(5 0 30 1 2 0 0)
+ SF-TOGGLE _"Work on copy" TRUE
+ SF-TOGGLE _"Keep bump layer" FALSE
+)
+
+(script-fu-menu-register "script-fu-add-bevel" "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/addborder.scm b/plug-ins/script-fu/scripts/addborder.scm
new file mode 100644
index 0000000..ed47feb
--- /dev/null
+++ b/plug-ins/script-fu/scripts/addborder.scm
@@ -0,0 +1,177 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Copyright (C) 1997 Andy Thomas alt@picnic.demon.co.uk
+;
+; Version 0.2 10.6.97 Changed to new script-fu interface in 0.99.10
+
+; Delta the color by the given amount. Check for boundary conditions
+; If < 0 set to zero
+; If > 255 set to 255
+; Return the new value
+
+(define (script-fu-addborder aimg adraw xsize ysize color dvalue)
+
+ (define (deltacolor col delta)
+ (let* ((newcol (+ col delta)))
+ (if (< newcol 0) (set! newcol 0))
+ (if (> newcol 255) (set! newcol 255))
+ newcol
+ )
+ )
+
+ (define (adjcolor col delta)
+ (mapcar (lambda (x) (deltacolor x delta)) col)
+ )
+
+ (define (gen_top_array xsize ysize owidth oheight width height)
+ (let* ((n_array (cons-array 10 'double)))
+ (aset n_array 0 0 )
+ (aset n_array 1 0 )
+ (aset n_array 2 xsize)
+ (aset n_array 3 ysize)
+ (aset n_array 4 (+ xsize owidth))
+ (aset n_array 5 ysize)
+ (aset n_array 6 width)
+ (aset n_array 7 0 )
+ (aset n_array 8 0 )
+ (aset n_array 9 0 )
+ n_array)
+ )
+
+ (define (gen_left_array xsize ysize owidth oheight width height)
+ (let* ((n_array (cons-array 10 'double)))
+ (aset n_array 0 0 )
+ (aset n_array 1 0 )
+ (aset n_array 2 xsize)
+ (aset n_array 3 ysize)
+ (aset n_array 4 xsize)
+ (aset n_array 5 (+ ysize oheight))
+ (aset n_array 6 0 )
+ (aset n_array 7 height )
+ (aset n_array 8 0 )
+ (aset n_array 9 0 )
+ n_array)
+ )
+
+ (define (gen_right_array xsize ysize owidth oheight width height)
+ (let* ((n_array (cons-array 10 'double)))
+ (aset n_array 0 width )
+ (aset n_array 1 0 )
+ (aset n_array 2 (+ xsize owidth))
+ (aset n_array 3 ysize)
+ (aset n_array 4 (+ xsize owidth))
+ (aset n_array 5 (+ ysize oheight))
+ (aset n_array 6 width)
+ (aset n_array 7 height)
+ (aset n_array 8 width )
+ (aset n_array 9 0 )
+ n_array)
+ )
+
+ (define (gen_bottom_array xsize ysize owidth oheight width height)
+ (let* ((n_array (cons-array 10 'double)))
+ (aset n_array 0 0 )
+ (aset n_array 1 height)
+ (aset n_array 2 xsize)
+ (aset n_array 3 (+ ysize oheight))
+ (aset n_array 4 (+ xsize owidth))
+ (aset n_array 5 (+ ysize oheight))
+ (aset n_array 6 width)
+ (aset n_array 7 height)
+ (aset n_array 8 0 )
+ (aset n_array 9 height)
+ n_array)
+ )
+
+ (let* ((img (car (gimp-item-get-image adraw)))
+ (owidth (car (gimp-image-width img)))
+ (oheight (car (gimp-image-height img)))
+ (width (+ owidth (* 2 xsize)))
+ (height (+ oheight (* 2 ysize)))
+ (layer (car (gimp-layer-new img
+ width height
+ (car (gimp-drawable-type-with-alpha adraw))
+ _"Border Layer" 100 LAYER-MODE-NORMAL))))
+
+ (gimp-context-push)
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+ (gimp-context-set-antialias FALSE)
+ (gimp-context-set-feather FALSE)
+
+ (gimp-image-undo-group-start img)
+
+ (gimp-image-resize img
+ width
+ height
+ xsize
+ ysize)
+
+ (gimp-image-insert-layer img layer 0 0)
+ (gimp-drawable-fill layer FILL-TRANSPARENT)
+
+ (gimp-context-set-background (adjcolor color dvalue))
+ (gimp-image-select-polygon img
+ CHANNEL-OP-REPLACE
+ 10
+ (gen_top_array xsize ysize owidth oheight width height))
+ (gimp-drawable-edit-fill layer FILL-BACKGROUND)
+ (gimp-context-set-background (adjcolor color (/ dvalue 2)))
+ (gimp-image-select-polygon img
+ CHANNEL-OP-REPLACE
+ 10
+ (gen_left_array xsize ysize owidth oheight width height))
+ (gimp-drawable-edit-fill layer FILL-BACKGROUND)
+ (gimp-context-set-background (adjcolor color (- 0 (/ dvalue 2))))
+ (gimp-image-select-polygon img
+ CHANNEL-OP-REPLACE
+ 10
+ (gen_right_array xsize ysize owidth oheight width height))
+
+ (gimp-drawable-edit-fill layer FILL-BACKGROUND)
+ (gimp-context-set-background (adjcolor color (- 0 dvalue)))
+ (gimp-image-select-polygon img
+ CHANNEL-OP-REPLACE
+ 10
+ (gen_bottom_array xsize ysize owidth oheight width height))
+
+ (gimp-drawable-edit-fill layer FILL-BACKGROUND)
+ (gimp-selection-none img)
+ (gimp-image-undo-group-end img)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-addborder"
+ _"Add _Border..."
+ _"Add a border around an image"
+ "Andy Thomas <alt@picnic.demon.co.uk>"
+ "Andy Thomas"
+ "6/10/97"
+ "*"
+ SF-IMAGE "Input image" 0
+ SF-DRAWABLE "Input drawable" 0
+ SF-ADJUSTMENT _"Border X size" '(12 1 250 1 10 0 1)
+ SF-ADJUSTMENT _"Border Y size" '(12 1 250 1 10 0 1)
+ SF-COLOR _"Border color" '(38 31 207)
+ SF-ADJUSTMENT _"Delta value on color" '(25 1 255 1 10 0 1)
+)
+
+(script-fu-menu-register "script-fu-addborder"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/blend-anim.scm b/plug-ins/script-fu/scripts/blend-anim.scm
new file mode 100644
index 0000000..517b1c5
--- /dev/null
+++ b/plug-ins/script-fu/scripts/blend-anim.scm
@@ -0,0 +1,242 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; blend-anim.scm version 1.03 1999/12/21
+;
+; CHANGE-LOG:
+; 1.00 - initial release
+; 1.01 - some code cleanup, no real changes
+; 1.02 - use gimp-message to output an error message if called
+; with less than three layers
+; 1.03 - only call blur plugin when blut-radius >= 1.0
+;
+; Copyright (C) 1997-1999 Sven Neumann <sven@gimp.org>
+;
+;
+; Blends two or more layers over a background, so that an animation can
+; be saved. A minimum of three layers is required.
+
+(define (script-fu-blend-anim img
+ drawable
+ frames
+ max-blur
+ looped)
+
+ (define (multi-raise-layer image layer times)
+ (while (> times 0)
+ (gimp-image-raise-item image layer)
+ (set! times (- times 1))
+ )
+ )
+
+ (let* (
+ (max-blur (max max-blur 0))
+ (frames (max frames 0))
+ (image (car (gimp-image-duplicate img)))
+ (width (car (gimp-image-width image)))
+ (height (car (gimp-image-height image)))
+ (layers (gimp-image-get-layers image))
+ (num-layers (car layers))
+ (layer-array (cadr layers))
+ (slots (- num-layers 2))
+ (bg-layer (aref layer-array (- num-layers 1)))
+ (max-width 0)
+ (max-height 0)
+ (offset-x 0)
+ (offset-y 0)
+ )
+
+ (if (> num-layers 2)
+ (begin
+ (gimp-image-undo-disable image)
+
+ (if (= looped TRUE)
+ ; add a copy of the lowest blend layer on top
+ (let* ((copy (car (gimp-layer-copy
+ (aref layer-array (- num-layers 2)) TRUE))))
+ (gimp-image-insert-layer image copy 0 0)
+ (set! layers (gimp-image-get-layers image))
+ (set! num-layers (car layers))
+ (set! layer-array (cadr layers))
+ (set! slots (- num-layers 2))
+ (set! bg-layer (aref layer-array (- num-layers 1)))))
+
+ ; make all layers invisible and check for sizes
+ (let* ((min-offset-x width)
+ (min-offset-y height)
+ (layer-count slots))
+ (gimp-item-set-visible bg-layer FALSE)
+ (while (> layer-count -1)
+ (let* ((layer (aref layer-array layer-count))
+ (layer-width (+ (car (gimp-drawable-width layer))
+ (* max-blur 2)))
+ (layer-height (+ (car (gimp-drawable-height layer))
+ (* max-blur 2)))
+ (layer-offsets (gimp-drawable-offsets layer))
+ (layer-offset-x (- (car layer-offsets) max-blur))
+ (layer-offset-y (- (cadr layer-offsets) max-blur)))
+ (gimp-item-set-visible layer FALSE)
+ (set! max-width (max max-width layer-width))
+ (set! max-height (max max-height layer-height))
+ (set! min-offset-x (min min-offset-x layer-offset-x))
+ (set! min-offset-y (min min-offset-y layer-offset-y))
+ (set! layer-count (- layer-count 1))))
+ (set! offset-x (- (car (gimp-drawable-offsets bg-layer))
+ min-offset-x))
+ (set! offset-y (- (cadr (gimp-drawable-offsets bg-layer))
+ min-offset-y)))
+
+ ; create intermediate frames by merging copies of adjacent layers
+ ; with the background layer
+ (let* ((layer-count slots))
+ (while (> layer-count 0)
+ (let* ((frame-count frames)
+ (lower-layer (aref layer-array layer-count))
+ (upper-layer (aref layer-array (- layer-count 1))))
+ (while (> frame-count 0)
+ (let* ((opacity (* (/ frame-count (+ frames 1)) 100))
+ (blur (/ (* opacity max-blur) 100))
+ (upper-copy (car (gimp-layer-copy upper-layer TRUE)))
+ (lower-copy (car (gimp-layer-copy lower-layer TRUE)))
+ (bg-copy (car (gimp-layer-copy bg-layer TRUE))))
+ (gimp-image-insert-layer image bg-copy 0 0)
+ (gimp-image-insert-layer image lower-copy 0 0)
+ (gimp-image-insert-layer image upper-copy 0 0)
+ (gimp-item-set-visible upper-copy TRUE)
+ (gimp-item-set-visible lower-copy TRUE)
+ (gimp-item-set-visible bg-copy TRUE)
+ (gimp-layer-set-opacity upper-copy (- 100 opacity))
+ (gimp-layer-set-opacity lower-copy opacity)
+ (gimp-layer-set-opacity bg-copy 100)
+ (if (> max-blur 0)
+ (let* ((layer-width (car (gimp-drawable-width upper-copy)))
+ (layer-height (car (gimp-drawable-height upper-copy))))
+ (gimp-layer-set-lock-alpha upper-copy FALSE)
+ (gimp-layer-resize upper-copy
+ (+ layer-width (* blur 2))
+ (+ layer-height (* blur 2))
+ blur
+ blur)
+ (if (>= blur 1.0)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ image
+ upper-copy
+ blur
+ TRUE TRUE))
+ (set! blur (- max-blur blur))
+ (gimp-layer-set-lock-alpha lower-copy FALSE)
+ (set! layer-width (car (gimp-drawable-width
+ lower-copy)))
+ (set! layer-height (car (gimp-drawable-height
+ lower-copy)))
+ (gimp-layer-resize lower-copy
+ (+ layer-width (* blur 2))
+ (+ layer-height (* blur 2))
+ blur
+ blur)
+ (if (>= blur 1.0)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ image
+ lower-copy
+ blur
+ TRUE TRUE))))
+ (gimp-layer-resize bg-copy
+ max-width
+ max-height
+ offset-x
+ offset-y)
+ (let* ((merged-layer (car (gimp-image-merge-visible-layers
+ image CLIP-TO-IMAGE))))
+ (gimp-item-set-visible merged-layer FALSE))
+ (set! frame-count (- frame-count 1))))
+ (set! layer-count (- layer-count 1)))))
+
+ ; merge all original blend layers but the lowest one
+ ; with copies of the background layer
+ (let* ((layer-count 0))
+ (while (< layer-count slots)
+ (let* ((orig-layer (aref layer-array layer-count))
+ (bg-copy (car (gimp-layer-copy bg-layer TRUE))))
+ (gimp-image-insert-layer image
+ bg-copy
+ -1
+ (* layer-count (+ frames 1)))
+ (multi-raise-layer image
+ orig-layer
+ (+ (* (- slots layer-count) frames) 1))
+ (gimp-item-set-visible orig-layer TRUE)
+ (gimp-item-set-visible bg-copy TRUE)
+ (gimp-layer-resize bg-copy
+ max-width
+ max-height
+ offset-x
+ offset-y)
+ (let* ((merged-layer (car (gimp-image-merge-visible-layers
+ image CLIP-TO-IMAGE))))
+ (gimp-item-set-visible merged-layer FALSE))
+ (set! layer-count (+ layer-count 1)))))
+
+ ; merge the lowest blend layer with the background layer
+ (let* ((orig-layer (aref layer-array (- num-layers 2))))
+ (gimp-item-set-visible bg-layer TRUE)
+ (gimp-item-set-visible orig-layer TRUE)
+ (gimp-image-merge-visible-layers image CLIP-TO-IMAGE))
+
+ ; make all layers visible again
+ (let* ((result-layers (gimp-image-get-layers image))
+ (num-result-layers (car result-layers))
+ (result-layer-array (cadr result-layers))
+ (layer-count (- num-result-layers 1)))
+ (while (> layer-count -1)
+ (let* ((layer (aref result-layer-array layer-count))
+ (name (string-append _"Frame" " "
+ (number->string
+ (- num-result-layers layer-count) 10))))
+ (gimp-item-set-visible layer TRUE)
+ (gimp-item-set-name layer name)
+ (set! layer-count (- layer-count 1))))
+
+ (if (= looped TRUE)
+ ; remove the topmost layer
+ (gimp-image-remove-layer image (aref result-layer-array 0))))
+
+ (gimp-image-undo-enable image)
+ (gimp-display-new image)
+ (gimp-displays-flush)
+ )
+
+ (gimp-message _"Blend Animation needs at least three source layers")
+ )
+ )
+)
+
+(script-fu-register "script-fu-blend-anim"
+ _"_Blend..."
+ _"Create intermediate layers to blend two or more layers over a background as an animation"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "1999/12/21"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Intermediate frames" '(3 1 1024 1 10 0 1)
+ SF-ADJUSTMENT _"Max. blur radius" '(0 0 1024 1 10 0 1)
+ SF-TOGGLE _"Looped" TRUE
+)
+
+(script-fu-menu-register "script-fu-blend-anim"
+ "<Image>/Filters/Animation/Animators")
diff --git a/plug-ins/script-fu/scripts/burn-in-anim.scm b/plug-ins/script-fu/scripts/burn-in-anim.scm
new file mode 100644
index 0000000..4842e8a
--- /dev/null
+++ b/plug-ins/script-fu/scripts/burn-in-anim.scm
@@ -0,0 +1,243 @@
+;
+; burn-in-anim.scm V2.1 - script-fu for GIMP 1.1 and higher
+;
+; Copyright (C) 9/2000 Roland Berger
+; roland@fuchur.leute.server.de
+; http://fuchur.leute.server.de
+;
+; Let text appear and fade out with a "burn-in" like SFX.
+; Works on an image with a text and a background layer
+;
+; Copying Policy: GNU Public License http://www.gnu.org
+;
+
+(define (script-fu-burn-in-anim org-img
+ org-layer
+ glow-color
+ fadeout
+ bl-width
+ corona-width
+ after-glow
+ show-glow
+ optimize
+ speed)
+
+ (let* (
+ ;--- main variable: "bl-x" runs from 0 to layer-width
+ (bl-x 0)
+ (frame-nr 0)
+ (img 0)
+ (source-layer 0)
+ (bg-source-layer 0)
+ (source-layer-width 0)
+ (bg-layer 0)
+ (bg-layer-name 0)
+ (bl-layer 0)
+ (bl-layer-name 0)
+ (bl-mask 0)
+ (bl-layer-width 0)
+ (bl-height 0)
+ (bl-x-off 0)
+ (bl-y-off 0)
+ (nofadeout-bl-x-off 0)
+ (nofadeout-bl-width 0)
+ (blended-layer 0)
+ (img-display 0)
+ )
+
+ (if (< speed 1)
+ (set! speed (* -1 speed)) )
+
+ ;--- check image and work on a copy
+ (if (and (= (car (gimp-image-get-layers org-img)) 2)
+ (= (car (gimp-image-get-floating-sel org-img)) -1))
+
+ ;--- main program structure starts here, begin of "if-1"
+ (begin
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (set! img (car (gimp-image-duplicate org-img)))
+ (gimp-image-undo-disable img)
+ (if (> (car (gimp-drawable-type org-layer)) 1 )
+ (gimp-image-convert-rgb img))
+ (set! source-layer (aref (cadr (gimp-image-get-layers img)) 0 ))
+ (set! bg-source-layer (aref (cadr (gimp-image-get-layers img)) 1 ))
+ (set! source-layer-width (car (gimp-drawable-width source-layer)))
+
+ ;--- hide layers, cause we want to "merge visible layers" later
+ (gimp-item-set-visible source-layer FALSE)
+ (gimp-item-set-visible bg-source-layer FALSE)
+
+ ;--- process image horizontal with pixel-speed
+ (while (< bl-x (+ source-layer-width bl-width))
+ (set! bl-layer (car (gimp-layer-copy source-layer TRUE)))
+ (set! bl-layer-name (string-append "fr-nr"
+ (number->string frame-nr 10) ) )
+
+ (gimp-image-insert-layer img bl-layer 0 -2)
+ (gimp-item-set-name bl-layer bl-layer-name)
+ (gimp-item-set-visible bl-layer TRUE)
+ (gimp-layer-set-lock-alpha bl-layer TRUE)
+ (gimp-layer-add-alpha bl-layer)
+
+ ;--- add an alpha mask for blending and select it
+ (gimp-image-select-item img CHANNEL-OP-REPLACE bl-layer)
+ (set! bl-mask (car (gimp-layer-create-mask bl-layer ADD-MASK-BLACK)))
+ (gimp-layer-add-mask bl-layer bl-mask)
+
+ ;--- handle layer geometry
+ (set! bl-layer-width source-layer-width)
+ (set! bl-height (car (gimp-drawable-height bl-layer)))
+ (set! bl-x-off (- bl-x bl-width))
+ (set! bl-x-off (+ bl-x-off (car (gimp-drawable-offsets bl-layer))))
+ (set! bl-y-off (cadr (gimp-drawable-offsets bl-layer)))
+
+ ;--- select a rectangular area to blend
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE bl-x-off bl-y-off bl-width bl-height)
+ ;--- select at least 1 pixel!
+ (gimp-image-select-rectangle img CHANNEL-OP-ADD bl-x-off bl-y-off (+ bl-width 1) bl-height)
+
+ (if (= fadeout FALSE)
+ (begin
+ (set! nofadeout-bl-x-off (car (gimp-drawable-offsets bl-layer)))
+ (set! nofadeout-bl-width (+ nofadeout-bl-x-off bl-x))
+ (set! nofadeout-bl-width (max nofadeout-bl-width 1))
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE
+ nofadeout-bl-x-off bl-y-off
+ nofadeout-bl-width bl-height)
+ )
+ )
+
+ ;--- alpha blending text to trans (fadeout)
+ (gimp-context-set-foreground '(255 255 255))
+ (gimp-context-set-background '( 0 0 0))
+ (if (= fadeout TRUE)
+ (begin
+ ; blend with 20% offset to get less transparency in the front
+ (gimp-context-set-gradient-fg-bg-rgb)
+ (gimp-drawable-edit-gradient-fill bl-mask
+ GRADIENT-LINEAR 20
+ FALSE 0 0
+ TRUE
+ (+ bl-x-off bl-width) 0
+ bl-x-off 0)
+ )
+ )
+
+ (if (= fadeout FALSE)
+ (begin
+ (gimp-context-set-foreground '(255 255 255))
+ (gimp-drawable-edit-fill bl-mask FILL-FOREGROUND)
+ )
+ )
+
+ (gimp-layer-remove-mask bl-layer MASK-APPLY)
+
+ ;--- add bright glow in front
+ (if (= show-glow TRUE)
+ (begin
+ ;--- add some brightness to whole text
+ (if (= fadeout TRUE)
+ (gimp-drawable-brightness-contrast bl-layer 0.787 0)
+ )
+
+ ;--- blend glow color inside the letters
+ (gimp-context-set-foreground glow-color)
+ (gimp-context-set-gradient-fg-transparent)
+ (gimp-drawable-edit-gradient-fill bl-layer
+ GRADIENT-LINEAR 0
+ FALSE 0 0
+ TRUE
+ (+ bl-x-off bl-width) 0
+ (- (+ bl-x-off bl-width) after-glow) 0)
+
+ ;--- add corona effect
+ (gimp-image-select-item img CHANNEL-OP-REPLACE bl-layer)
+ (gimp-selection-sharpen img)
+ (gimp-selection-grow img corona-width)
+ (gimp-layer-set-lock-alpha bl-layer FALSE)
+ (gimp-selection-feather img corona-width)
+ (gimp-context-set-foreground glow-color)
+ (gimp-drawable-edit-gradient-fill bl-layer
+ GRADIENT-LINEAR 0
+ FALSE 0 0
+ TRUE
+ (- (+ bl-x-off bl-width) corona-width) 0
+ (- (+ bl-x-off bl-width) after-glow) 0)
+ )
+ )
+
+ ;--- merge with bg layer
+ (set! bg-layer (car (gimp-layer-copy bg-source-layer FALSE)))
+ (gimp-image-insert-layer img bg-layer 0 -1)
+ (gimp-image-lower-item img bg-layer)
+ (set! bg-layer-name (string-append "bg-"
+ (number->string frame-nr 10)))
+ (gimp-item-set-name bg-layer bg-layer-name)
+ (gimp-item-set-visible bg-layer TRUE)
+ (set! blended-layer (car (gimp-image-merge-visible-layers img
+ CLIP-TO-IMAGE)))
+ ;(set! blended-layer bl-layer)
+ (gimp-item-set-visible blended-layer FALSE)
+
+ ;--- end of "while" loop
+ (set! frame-nr (+ frame-nr 1))
+ (set! bl-x (+ bl-x speed))
+ )
+
+ ;--- finalize the job
+ (gimp-selection-none img)
+ (gimp-image-remove-layer img source-layer)
+ (gimp-image-remove-layer img bg-source-layer)
+
+ (gimp-image-set-filename img "burn-in")
+
+ (if (= optimize TRUE)
+ (begin
+ (gimp-image-convert-indexed img CONVERT-DITHER-FS CONVERT-PALETTE-WEB 250 FALSE TRUE "")
+ (set! img (car (plug-in-animationoptimize RUN-NONINTERACTIVE
+ img
+ blended-layer)))
+ )
+ )
+
+ (gimp-item-set-visible (aref (cadr (gimp-image-get-layers img)) 0)
+ TRUE)
+ (gimp-image-undo-enable img)
+ (gimp-image-clean-all img)
+ (set! img-display (car (gimp-display-new img)))
+
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+
+ ;--- false form of "if-1"
+ (gimp-message _"The Burn-In script needs two layers in total. A foreground layer with transparency and a background layer.")
+ )
+ )
+)
+
+
+(script-fu-register "script-fu-burn-in-anim"
+ _"B_urn-In..."
+ _"Create intermediate layers to produce an animated 'burn-in' transition between two layers"
+ "Roland Berger roland@fuchur.leute.server.de"
+ "Roland Berger"
+ "January 2001"
+ "RGBA GRAYA INDEXEDA"
+ SF-IMAGE "The image" 0
+ SF-DRAWABLE "Layer to animate" 0
+ SF-COLOR _"Glow color" "white"
+ SF-TOGGLE _"Fadeout" FALSE
+ SF-VALUE _"Fadeout width" "100"
+ SF-VALUE _"Corona width" "7"
+ SF-VALUE _"After glow" "50"
+ SF-TOGGLE _"Add glowing" TRUE
+ SF-TOGGLE _"Prepare for GIF" FALSE
+ SF-VALUE _"Speed (pixels/frame)" "50"
+)
+
+(script-fu-menu-register "script-fu-burn-in-anim"
+ "<Image>/Filters/Animation/Animators")
diff --git a/plug-ins/script-fu/scripts/carve-it.scm b/plug-ins/script-fu/scripts/carve-it.scm
new file mode 100644
index 0000000..a88fa08
--- /dev/null
+++ b/plug-ins/script-fu/scripts/carve-it.scm
@@ -0,0 +1,205 @@
+; CARVE-IT
+; Carving, embossing, & stamping
+; Process taken from "The Photoshop 3 WOW! Book"
+; http://www.peachpit.com
+; This script requires a grayscale image containing a single layer.
+; This layer is used as the mask for the carving effect
+; NOTE: This script requires the image to be carved to either be an
+; RGB color or grayscale image with a single layer. An indexed file
+; can not be used due to the use of gimp-drawable-histogram and
+; gimp-drawable-levels.
+
+
+(define (carve-scale val scale)
+ (* (sqrt val) scale))
+
+(define (calculate-inset-gamma img layer)
+ (let* ((stats (gimp-drawable-histogram layer 0 0.0 1.0))
+ (mean (car stats)))
+ (cond ((< mean 127) (+ 1.0 (* 0.5 (/ (- 127 mean) 127.0))))
+ ((>= mean 127) (- 1.0 (* 0.5 (/ (- mean 127) 127.0)))))))
+
+
+(define (copy-layer-carve-it dest-image dest-drawable source-image source-drawable)
+ (gimp-selection-all dest-image)
+ (gimp-drawable-edit-clear dest-drawable)
+ (gimp-selection-none dest-image)
+ (gimp-selection-all source-image)
+ (gimp-edit-copy source-drawable)
+ (let ((floating-sel (car (gimp-edit-paste dest-drawable FALSE))))
+ (gimp-floating-sel-anchor floating-sel)))
+
+
+
+(define (script-fu-carve-it mask-img mask-drawable bg-layer carve-white)
+ (let* (
+ (width (car (gimp-drawable-width mask-drawable)))
+ (height (car (gimp-drawable-height mask-drawable)))
+ (type (car (gimp-drawable-type bg-layer)))
+ (img (car (gimp-image-new width height (cond ((= type RGB-IMAGE) RGB)
+ ((= type RGBA-IMAGE) RGB)
+ ((= type GRAY-IMAGE) GRAY)
+ ((= type GRAYA-IMAGE) GRAY)
+ ((= type INDEXED-IMAGE) INDEXED)
+ ((= type INDEXEDA-IMAGE) INDEXED)))))
+ (size (min width height))
+ (offx (carve-scale size 0.33))
+ (offy (carve-scale size 0.25))
+ (feather (carve-scale size 0.3))
+ (brush-size (carve-scale size 0.3))
+ (brush-name (car (gimp-brush-new "Carve It")))
+ (mask-fs 0)
+ (mask (car (gimp-channel-new img width height "Engraving Mask" 50 '(0 0 0))))
+ (inset-gamma (calculate-inset-gamma (car (gimp-item-get-image bg-layer)) bg-layer))
+ (mask-fat 0)
+ (mask-emboss 0)
+ (mask-highlight 0)
+ (mask-shadow 0)
+ (shadow-layer 0)
+ (highlight-layer 0)
+ (cast-shadow-layer 0)
+ (csl-mask 0)
+ (inset-layer 0)
+ (il-mask 0)
+ (bg-width (car (gimp-drawable-width bg-layer)))
+ (bg-height (car (gimp-drawable-height bg-layer)))
+ (bg-type (car (gimp-drawable-type bg-layer)))
+ (bg-image (car (gimp-item-get-image bg-layer)))
+ (layer1 (car (gimp-layer-new img bg-width bg-height bg-type "Layer1" 100 LAYER-MODE-NORMAL)))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable img)
+
+ (gimp-image-insert-layer img layer1 0 0)
+
+ (gimp-selection-all img)
+ (gimp-drawable-edit-clear layer1)
+ (gimp-selection-none img)
+ (copy-layer-carve-it img layer1 bg-image bg-layer)
+
+ (gimp-edit-copy mask-drawable)
+ (gimp-image-insert-channel img mask -1 0)
+
+ (plug-in-tile RUN-NONINTERACTIVE img layer1 width height FALSE)
+ (set! mask-fs (car (gimp-edit-paste mask FALSE)))
+ (gimp-floating-sel-anchor mask-fs)
+ (if (= carve-white FALSE)
+ (gimp-drawable-invert mask FALSE))
+
+ (set! mask-fat (car (gimp-channel-copy mask)))
+ (gimp-image-insert-channel img mask-fat -1 0)
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask-fat)
+
+ (gimp-brush-set-shape brush-name BRUSH-GENERATED-CIRCLE)
+ (gimp-brush-set-spikes brush-name 2)
+ (gimp-brush-set-hardness brush-name 1.0)
+ (gimp-brush-set-spacing brush-name 25)
+ (gimp-brush-set-aspect-ratio brush-name 1)
+ (gimp-brush-set-angle brush-name 0)
+ (cond (<= brush-size 17) (gimp-brush-set-radius brush-name (\ brush-size 2))
+ (else gimp-brush-set-radius brush-name (\ 19 2)))
+ (gimp-context-set-brush brush-name)
+
+ (gimp-context-set-foreground '(255 255 255))
+ (gimp-drawable-edit-stroke-selection mask-fat)
+ (gimp-selection-none img)
+
+ (set! mask-emboss (car (gimp-channel-copy mask-fat)))
+ (gimp-image-insert-channel img mask-emboss -1 0)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img mask-emboss feather TRUE TRUE)
+ (plug-in-emboss RUN-NONINTERACTIVE img mask-emboss 315.0 45.0 7 TRUE)
+
+ (gimp-context-set-background '(180 180 180))
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask-fat)
+ (gimp-selection-invert img)
+ (gimp-drawable-edit-fill mask-emboss FILL-BACKGROUND)
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask)
+ (gimp-drawable-edit-fill mask-emboss FILL-BACKGROUND)
+ (gimp-selection-none img)
+
+ (set! mask-highlight (car (gimp-channel-copy mask-emboss)))
+ (gimp-image-insert-channel img mask-highlight -1 0)
+ (gimp-drawable-levels mask-highlight 0
+ 0.7056 1.0 TRUE
+ 1.0
+ 0.0 1.0 TRUE)
+
+ (set! mask-shadow mask-emboss)
+ (gimp-drawable-levels mask-shadow 0
+ 0.0 0.70586 TRUE
+ 1.0
+ 0.0 1.0 TRUE)
+
+ (gimp-edit-copy mask-shadow)
+ (set! shadow-layer (car (gimp-edit-paste layer1 FALSE)))
+ (gimp-floating-sel-to-layer shadow-layer)
+ (gimp-layer-set-mode shadow-layer LAYER-MODE-MULTIPLY)
+
+ (gimp-edit-copy mask-highlight)
+ (set! highlight-layer (car (gimp-edit-paste shadow-layer FALSE)))
+ (gimp-floating-sel-to-layer highlight-layer)
+ (gimp-layer-set-mode highlight-layer LAYER-MODE-SCREEN)
+
+ (gimp-edit-copy mask)
+ (set! cast-shadow-layer (car (gimp-edit-paste highlight-layer FALSE)))
+ (gimp-floating-sel-to-layer cast-shadow-layer)
+ (gimp-layer-set-mode cast-shadow-layer LAYER-MODE-MULTIPLY)
+ (gimp-layer-set-opacity cast-shadow-layer 75)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img cast-shadow-layer feather TRUE TRUE)
+ (gimp-item-transform-translate cast-shadow-layer offx offy)
+
+ (set! csl-mask (car (gimp-layer-create-mask cast-shadow-layer ADD-MASK-BLACK)))
+ (gimp-layer-add-mask cast-shadow-layer csl-mask)
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask)
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill csl-mask FILL-BACKGROUND)
+
+ (set! inset-layer (car (gimp-layer-copy layer1 TRUE)))
+ (gimp-image-insert-layer img inset-layer 0 1)
+
+ (set! il-mask (car (gimp-layer-create-mask inset-layer ADD-MASK-BLACK)))
+ (gimp-layer-add-mask inset-layer il-mask)
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask)
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill il-mask FILL-BACKGROUND)
+ (gimp-selection-none img)
+ (gimp-selection-none bg-image)
+ (gimp-drawable-levels inset-layer 0 0.0 1.0 TRUE inset-gamma 0.0 1.0 TRUE)
+ (gimp-image-remove-channel img mask)
+ (gimp-image-remove-channel img mask-fat)
+ (gimp-image-remove-channel img mask-highlight)
+ (gimp-image-remove-channel img mask-shadow)
+
+ (gimp-item-set-name layer1 _"Carved Surface")
+ (gimp-item-set-name shadow-layer _"Bevel Shadow")
+ (gimp-item-set-name highlight-layer _"Bevel Highlight")
+ (gimp-item-set-name cast-shadow-layer _"Cast Shadow")
+ (gimp-item-set-name inset-layer _"Inset")
+
+ (gimp-brush-delete brush-name)
+
+ (gimp-display-new img)
+ (gimp-image-undo-enable img)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-carve-it"
+ _"Stencil C_arve..."
+ _"Use the specified drawable as a stencil to carve from the specified image."
+ "Spencer Kimball"
+ "Spencer Kimball"
+ "1997"
+ "GRAY"
+ SF-IMAGE "Mask image" 0
+ SF-DRAWABLE "Mask drawable" 0
+ SF-DRAWABLE _"Image to carve" 0
+ SF-TOGGLE _"Carve white areas" TRUE
+)
+
+(script-fu-menu-register "script-fu-carve-it"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/chrome-it.scm b/plug-ins/script-fu/scripts/chrome-it.scm
new file mode 100644
index 0000000..761ac47
--- /dev/null
+++ b/plug-ins/script-fu/scripts/chrome-it.scm
@@ -0,0 +1,252 @@
+; CHROME-IT
+; State of the art chrome effect for user-specified mask
+; This script requires a grayscale image containing a single layer.
+; This layer is used as the mask for the SOTA chrome effect
+
+(define (script-fu-sota-chrome-it mask-img mask-drawable chrome-saturation
+ chrome-lightness chrome-factor env-map hc cc carve-white)
+
+ (define (set-pt a index x y)
+ (begin
+ (aset a (* index 2) x)
+ (aset a (+ (* index 2) 1) y)
+ )
+ )
+
+ (define (spline-chrome-it)
+ (let* ((a (cons-array 18 'double)))
+ (set-pt a 0 0.0 0.0)
+ (set-pt a 1 0.125 0.9216)
+ (set-pt a 2 0.25 0.0902)
+ (set-pt a 3 0.375 0.9020)
+ (set-pt a 4 0.5 0.0989)
+ (set-pt a 5 0.625 0.9549)
+ (set-pt a 6 0.75 00784)
+ (set-pt a 7 0.875 0.9412)
+ (set-pt a 8 1.0 0.1216)
+ a
+ )
+ )
+
+
+ (define (shadows val)
+ (/ (* 0.96 val) 2.55)
+ )
+
+ (define (midtones val)
+ (/ val 2.55)
+ )
+
+ (define (highlights val)
+ ; The result is used as "gimp-drawable-color-balance" color parameter
+ ; and thus must be restricted to -100.0 <= highlights <= 100.0.
+ (min (/ (* 1.108 val) 2.55) 100.0)
+ )
+
+ (define (rval col)
+ (car col)
+ )
+
+ (define (gval col)
+ (cadr col)
+ )
+
+ (define (bval col)
+ (caddr col)
+ )
+
+ (define (sota-scale val scale chrome-factor)
+ (* (sqrt val) (* scale chrome-factor))
+ )
+
+ (define (copy-layer-chrome-it dest-image dest-drawable source-image source-drawable)
+ (gimp-selection-all dest-image)
+ (gimp-drawable-edit-clear dest-drawable)
+ (gimp-selection-none dest-image)
+ (gimp-selection-all source-image)
+ (gimp-edit-copy source-drawable)
+ (let (
+ (floating-sel (car (gimp-edit-paste dest-drawable FALSE)))
+ )
+ (gimp-floating-sel-anchor floating-sel)
+ )
+ )
+
+ (let* (
+ (banding-img (car (gimp-file-load RUN-NONINTERACTIVE env-map env-map)))
+ (banding-layer (car (gimp-image-get-active-drawable banding-img)))
+ (banding-height (car (gimp-drawable-height banding-layer)))
+ (banding-width (car (gimp-drawable-width banding-layer)))
+ (banding-type (car (gimp-drawable-type banding-layer)))
+ (width (car (gimp-drawable-width mask-drawable)))
+ (height (car (gimp-drawable-height mask-drawable)))
+ (img (car (gimp-image-new width height GRAY)))
+ (size (min width height))
+ (offx1 (sota-scale size 0.33 chrome-factor))
+ (offy1 (sota-scale size 0.25 chrome-factor))
+ (offx2 (sota-scale size (- 0.33) chrome-factor))
+ (offy2 (sota-scale size (- 0.25) chrome-factor))
+ (feather (sota-scale size 0.5 chrome-factor))
+ (brush-size (sota-scale size 0.5 chrome-factor))
+ (brush-name (car (gimp-brush-new "Chrome It")))
+ (mask (car (gimp-channel-new img width height "Chrome Stencil" 50 '(0 0 0))))
+ (bg-layer (car (gimp-layer-new img width height GRAY-IMAGE _"Background" 100 LAYER-MODE-NORMAL)))
+ (layer1 (car (gimp-layer-new img banding-width banding-height banding-type _"Layer 1" 100 LAYER-MODE-NORMAL)))
+ (layer2 (car (gimp-layer-new img width height GRAYA-IMAGE _"Layer 2" 100 LAYER-MODE-DIFFERENCE)))
+ (layer3 (car (gimp-layer-new img width height GRAYA-IMAGE _"Layer 3" 100 LAYER-MODE-NORMAL)))
+ (shadow (car (gimp-layer-new img width height GRAYA-IMAGE _"Drop Shadow" 100 LAYER-MODE-NORMAL)))
+ (mask-fs 0)
+ (layer-mask 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable img)
+
+ (gimp-image-insert-channel img mask -1 0)
+ (gimp-image-insert-layer img bg-layer 0 0)
+ (gimp-image-insert-layer img shadow 0 0)
+ (gimp-image-insert-layer img layer3 0 0)
+ (gimp-image-insert-layer img layer2 0 0)
+
+ (gimp-edit-copy mask-drawable)
+ (set! mask-fs (car (gimp-edit-paste mask FALSE)))
+ (gimp-floating-sel-anchor mask-fs)
+ (if (= carve-white FALSE)
+ (gimp-drawable-invert mask FALSE)
+ )
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-selection-none img)
+ (gimp-drawable-edit-fill layer2 FILL-BACKGROUND)
+ (gimp-drawable-edit-fill layer3 FILL-BACKGROUND)
+ (gimp-drawable-edit-clear shadow)
+
+ (gimp-item-set-visible bg-layer FALSE)
+ (gimp-item-set-visible shadow FALSE)
+
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask)
+ (gimp-context-set-background '(0 0 0))
+ (gimp-selection-translate img offx1 offy1)
+ (gimp-selection-feather img feather)
+ (gimp-drawable-edit-fill layer2 FILL-BACKGROUND)
+ (gimp-selection-translate img (* 2 offx2) (* 2 offy2))
+ (gimp-drawable-edit-fill layer3 FILL-BACKGROUND)
+ (gimp-selection-none img)
+ (set! layer2 (car (gimp-image-merge-visible-layers img CLIP-TO-IMAGE)))
+ (gimp-drawable-invert layer2 FALSE)
+
+ (gimp-image-insert-layer img layer1 0 0)
+ (copy-layer-chrome-it img layer1 banding-img banding-layer)
+ (gimp-image-delete banding-img)
+ (gimp-layer-scale layer1 width height FALSE)
+ (plug-in-gauss-iir RUN-NONINTERACTIVE img layer1 10 TRUE TRUE)
+ (gimp-layer-set-opacity layer1 50)
+ (set! layer1 (car (gimp-image-merge-visible-layers img CLIP-TO-IMAGE)))
+ (gimp-drawable-curves-spline layer1 HISTOGRAM-VALUE 18 (spline-chrome-it))
+
+ (set! layer-mask (car (gimp-layer-create-mask layer1 ADD-MASK-BLACK)))
+ (gimp-layer-add-mask layer1 layer-mask)
+ (gimp-image-select-item img CHANNEL-OP-REPLACE mask)
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill layer-mask FILL-BACKGROUND)
+
+ (set! layer2 (car (gimp-layer-copy layer1 TRUE)))
+ (gimp-image-insert-layer img layer2 0 0)
+
+ (gimp-brush-set-shape brush-name BRUSH-GENERATED-CIRCLE)
+ (gimp-brush-set-spikes brush-name 2)
+ (gimp-brush-set-hardness brush-name 1.0)
+ (gimp-brush-set-spacing brush-name 25)
+ (gimp-brush-set-aspect-ratio brush-name 1)
+ (gimp-brush-set-angle brush-name 0)
+ (cond (<= brush-size 17) (gimp-brush-set-radius brush-name (\ brush-size 2))
+ (else gimp-brush-set-radius brush-name (\ 19 2)))
+ (gimp-context-set-brush brush-name)
+
+ (gimp-context-set-foreground '(255 255 255))
+ (gimp-drawable-edit-stroke-selection layer-mask)
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-selection-feather img (* feather 1.5))
+ (gimp-selection-translate img (* 2.5 offx1) (* 2.5 offy1))
+ (gimp-drawable-edit-fill shadow FILL-BACKGROUND)
+
+ (gimp-selection-all img)
+ (gimp-context-set-pattern "Marble #1")
+ (gimp-drawable-edit-fill bg-layer FILL-PATTERN)
+ (gimp-selection-none img)
+
+ (gimp-image-convert-rgb img)
+
+ (gimp-drawable-color-balance layer1 TRANSFER-SHADOWS TRUE
+ (shadows (rval hc))
+ (shadows (gval hc))
+ (shadows (bval hc)))
+ (gimp-drawable-color-balance layer1 TRANSFER-MIDTONES TRUE
+ (midtones (rval hc))
+ (midtones (gval hc))
+ (midtones (bval hc)))
+ (gimp-drawable-color-balance layer1 TRANSFER-HIGHLIGHTS TRUE
+ (highlights (rval hc))
+ (highlights (gval hc))
+ (highlights (bval hc)))
+
+ (gimp-drawable-color-balance layer2 TRANSFER-SHADOWS TRUE
+ (shadows (rval cc))
+ (shadows (gval cc))
+ (shadows (bval cc)))
+ (gimp-drawable-color-balance layer2 TRANSFER-MIDTONES TRUE
+ (midtones (rval cc))
+ (midtones (gval cc))
+ (midtones (bval cc)))
+ (gimp-drawable-color-balance layer2 TRANSFER-HIGHLIGHTS TRUE
+ (highlights (rval cc))
+ (highlights (gval cc))
+ (highlights (bval cc)))
+ (gimp-drawable-hue-saturation layer2 HUE-RANGE-ALL
+ 0.0
+ chrome-lightness
+ chrome-saturation
+ 0.0)
+
+ (gimp-item-set-visible shadow TRUE)
+ (gimp-item-set-visible bg-layer TRUE)
+
+ (gimp-item-set-name layer2 _"Chrome")
+ (gimp-item-set-name layer1 _"Highlight")
+
+ (gimp-image-remove-channel img mask)
+
+ (gimp-brush-delete brush-name)
+
+ (gimp-display-new img)
+ (gimp-image-undo-enable img)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-sota-chrome-it"
+ _"Stencil C_hrome..."
+ _"Add a chrome effect to the selected region (or alpha) using a specified (grayscale) stencil"
+ "Spencer Kimball"
+ "Spencer Kimball"
+ "1997"
+ "GRAY"
+ SF-IMAGE "Chrome image" 0
+ SF-DRAWABLE "Chrome mask" 0
+ SF-ADJUSTMENT _"Chrome saturation" '(-80 -100 100 1 10 0 0)
+ SF-ADJUSTMENT _"Chrome lightness" '(-47 -100 100 1 10 0 0)
+ SF-ADJUSTMENT _"Chrome factor" '(0.75 0 1 0.1 0.01 2 0)
+ SF-FILENAME _"Environment map"
+ (string-append gimp-data-directory
+ "/scripts/images/beavis.jpg")
+ SF-COLOR _"Highlight balance" '(211 95 0)
+ SF-COLOR _"Chrome balance" "black"
+ SF-TOGGLE _"Chrome white areas" TRUE
+)
+
+(script-fu-menu-register "script-fu-sota-chrome-it"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/circuit.scm b/plug-ins/script-fu/scripts/circuit.scm
new file mode 100644
index 0000000..174a155
--- /dev/null
+++ b/plug-ins/script-fu/scripts/circuit.scm
@@ -0,0 +1,143 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Circuit board effect
+; Copyright (c) 1997 Adrian Likins
+;
+; Generates what looks a little like the back of an old circuit board.
+; Looks even better when gradient-mapp'ed with a suitable gradient.
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-circuit image
+ drawable
+ mask-size
+ seed
+ remove-bg
+ keep-selection
+ separate-layer)
+ (let* (
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (image-height (car (gimp-image-height image)))
+ (active-selection 0)
+ (from-selection 0)
+ (selection-bounds 0)
+ (select-offset-x 0)
+ (select-offset-y 0)
+ (select-width 0)
+ (select-height 0)
+ (effect-layer 0)
+ (active-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-group-start image)
+
+ (gimp-layer-add-alpha drawable)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! active-selection (car (gimp-selection-save image)))
+ (set! from-selection FALSE))
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))))
+
+ (set! selection-bounds (gimp-selection-bounds image))
+ (set! select-offset-x (cadr selection-bounds))
+ (set! select-offset-y (caddr selection-bounds))
+ (set! select-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (set! select-height (- (caddr (cddr selection-bounds)) select-offset-y))
+
+ (if (= separate-layer TRUE)
+ (begin
+ (set! effect-layer (car (gimp-layer-new image
+ select-width
+ select-height
+ type
+ _"Effect layer"
+ 100
+ LAYER-MODE-NORMAL)))
+
+ (gimp-image-insert-layer image effect-layer 0 -1)
+ (gimp-layer-set-offsets effect-layer select-offset-x select-offset-y)
+ (gimp-selection-none image)
+ (gimp-drawable-edit-clear effect-layer)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-edit-copy drawable)
+
+ (let ((floating-sel (car (gimp-edit-paste effect-layer FALSE))))
+ (gimp-floating-sel-anchor floating-sel)
+ )
+ (gimp-image-set-active-layer image effect-layer ))
+ (set! effect-layer drawable)
+ )
+ (set! active-layer effect-layer)
+
+ (if (= remove-bg TRUE)
+ (gimp-context-set-foreground '(0 0 0))
+ (gimp-context-set-foreground '(14 14 14))
+ )
+
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (plug-in-maze RUN-NONINTERACTIVE image active-layer 5 5 TRUE 0 seed 57 1)
+ (plug-in-oilify RUN-NONINTERACTIVE image active-layer mask-size 0)
+ (plug-in-edge RUN-NONINTERACTIVE image active-layer 2 1 0)
+ (if (= type RGBA-IMAGE)
+ (gimp-drawable-desaturate active-layer DESATURATE-LIGHTNESS))
+
+ (if (and
+ (= remove-bg TRUE)
+ (= separate-layer TRUE))
+ (begin
+ (gimp-image-select-color image CHANNEL-OP-REPLACE active-layer '(0 0 0))
+ (gimp-drawable-edit-clear active-layer)))
+
+ (if (= keep-selection FALSE)
+ (gimp-selection-none image))
+
+ (gimp-image-remove-channel image active-selection)
+ (gimp-image-set-active-layer image drawable)
+
+ (gimp-image-undo-group-end image)
+
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-circuit"
+ _"_Circuit..."
+ _"Fill the selected region (or alpha) with traces like those on a circuit board"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "10/17/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Oilify mask size" '(17 3 50 1 10 0 1)
+ SF-ADJUSTMENT _"Circuit seed" '(3 1 3000000 1 10 0 1)
+ SF-TOGGLE _"No background (only for separate layer)" FALSE
+ SF-TOGGLE _"Keep selection" TRUE
+ SF-TOGGLE _"Separate layer" TRUE
+)
+
+(script-fu-menu-register "script-fu-circuit"
+ "<Image>/Filters/Render")
diff --git a/plug-ins/script-fu/scripts/clothify.scm b/plug-ins/script-fu/scripts/clothify.scm
new file mode 100644
index 0000000..7b6f101
--- /dev/null
+++ b/plug-ins/script-fu/scripts/clothify.scm
@@ -0,0 +1,68 @@
+; CLOTHIFY version 1.02
+; Gives the current layer in the indicated image a cloth-like texture.
+; Process invented by Zach Beane (Xath@irc.gimp.net)
+;
+; Tim Newsome <drz@froody.bloke.com> 4/11/97
+
+(define (script-fu-clothify timg tdrawable bx by azimuth elevation depth)
+ (let* (
+ (width (car (gimp-drawable-width tdrawable)))
+ (height (car (gimp-drawable-height tdrawable)))
+ (img (car (gimp-image-new width height RGB)))
+; (layer-two (car (gimp-layer-new img width height RGB-IMAGE "Y Dots" 100 LAYER-MODE-MULTIPLY)))
+ (layer-one (car (gimp-layer-new img width height RGB-IMAGE "X Dots" 100 LAYER-MODE-NORMAL)))
+ (layer-two 0)
+ (bump-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable img)
+
+ (gimp-image-insert-layer img layer-one 0 0)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill layer-one FILL-BACKGROUND)
+
+ (plug-in-noisify RUN-NONINTERACTIVE img layer-one FALSE 0.7 0.7 0.7 0.7)
+
+ (set! layer-two (car (gimp-layer-copy layer-one 0)))
+ (gimp-layer-set-mode layer-two LAYER-MODE-MULTIPLY)
+ (gimp-image-insert-layer img layer-two 0 0)
+
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img layer-one bx TRUE FALSE)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img layer-two by FALSE TRUE)
+ (gimp-image-flatten img)
+ (set! bump-layer (car (gimp-image-get-active-layer img)))
+
+ (plug-in-c-astretch RUN-NONINTERACTIVE img bump-layer)
+ (plug-in-noisify RUN-NONINTERACTIVE img bump-layer FALSE 0.2 0.2 0.2 0.2)
+
+ (plug-in-bump-map RUN-NONINTERACTIVE img tdrawable bump-layer azimuth elevation depth 0 0 0 0 FALSE FALSE 0)
+ (gimp-image-delete img)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+
+(script-fu-register "script-fu-clothify"
+ _"_Clothify..."
+ _"Add a cloth-like texture to the selected region (or alpha)"
+ "Tim Newsome <drz@froody.bloke.com>"
+ "Tim Newsome"
+ "4/11/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Input image" 0
+ SF-DRAWABLE "Input drawable" 0
+ SF-ADJUSTMENT _"Blur X" '(9 3 100 1 10 0 1)
+ SF-ADJUSTMENT _"Blur Y" '(9 3 100 1 10 0 1)
+ SF-ADJUSTMENT _"Azimuth" '(135 0 360 1 10 1 0)
+ SF-ADJUSTMENT _"Elevation" '(45 0 90 1 10 1 0)
+ SF-ADJUSTMENT _"Depth" '(3 1 50 1 10 0 1)
+)
+
+(script-fu-menu-register "script-fu-clothify"
+ "<Image>/Filters/Artistic")
diff --git a/plug-ins/script-fu/scripts/coffee.scm b/plug-ins/script-fu/scripts/coffee.scm
new file mode 100644
index 0000000..d72bcb7
--- /dev/null
+++ b/plug-ins/script-fu/scripts/coffee.scm
@@ -0,0 +1,94 @@
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-coffee-stain inImage inLayer inNumber inDark)
+ (let* (
+ (theImage inImage)
+ (theHeight (car (gimp-image-height theImage)))
+ (theWidth (car (gimp-image-width theImage)))
+ (theNumber inNumber)
+ (theSize (min theWidth theHeight))
+ (theStain 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-group-start theImage)
+
+ (while (> theNumber 0)
+ (set! theNumber (- theNumber 1))
+ (set! theStain (car (gimp-layer-new theImage theSize theSize
+ RGBA-IMAGE _"Stain" 100
+ (if (= inDark TRUE)
+ LAYER-MODE-DARKEN-ONLY LAYER-MODE-NORMAL))))
+
+ (gimp-image-insert-layer theImage theStain 0 0)
+ (gimp-selection-all theImage)
+ (gimp-drawable-edit-clear theStain)
+
+ (let ((blobSize (/ (rand (- theSize 40)) (+ (rand 3) 1))))
+ (gimp-image-select-ellipse theImage
+ CHANNEL-OP-REPLACE
+ (/ (- theSize blobSize) 2)
+ (/ (- theSize blobSize) 2)
+ blobSize blobSize)
+ )
+
+ (script-fu-distress-selection theImage theStain
+ (- (* (+ (rand 15) 1) (+ (rand 15) 1)) 1)
+ (/ theSize 25) 4 2 TRUE TRUE)
+
+ (gimp-context-set-gradient "Coffee")
+
+ (gimp-drawable-edit-gradient-fill theStain
+ GRADIENT-SHAPEBURST-DIMPLED 0
+ FALSE 0 0
+ TRUE
+ 0 0 0 0)
+
+ (gimp-layer-set-offsets theStain
+ (- (rand theWidth) (/ theSize 2))
+ (- (rand theHeight) (/ theSize 2)))
+ )
+
+ (gimp-selection-none theImage)
+
+ (gimp-image-undo-group-end theImage)
+
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+; Register the function with GIMP:
+
+(script-fu-register "script-fu-coffee-stain"
+ _"_Coffee Stain..."
+ _"Add realistic looking coffee stains to the image"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "25th April 1998"
+ "RGB*"
+ SF-IMAGE "The image" 0
+ SF-DRAWABLE "The layer" 0
+ SF-ADJUSTMENT _"Stains" '(3 1 10 1 1 0 0)
+ SF-TOGGLE _"Darken only" TRUE
+)
+
+(script-fu-menu-register "script-fu-coffee-stain" "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/contactsheet.scm b/plug-ins/script-fu/scripts/contactsheet.scm
new file mode 100644
index 0000000..5f7520e
--- /dev/null
+++ b/plug-ins/script-fu/scripts/contactsheet.scm
@@ -0,0 +1,337 @@
+; "Contact Sheet" v1.2 September 5, 2007
+; by Kevin Cozens <kcozens@interlog.com>
+;
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Version 1.0 (July 27, 2004)
+; Created
+;
+; Version 1.1 (September 2, 2004)
+; Added ability to select sheet size, set font used for sheet and image
+;
+; Version 1.2 (September 5, 2007)
+; Preserve aspect ratio of original image. Center thumbnail in the area
+; allowed for the thumbnail. Added disable/enable of undo operations.
+; Added 1600x1200 sheet size.
+
+(define (script-fu-contactsheet dir sheet-size
+ title-font legend-font text-color bg-color)
+
+ (define (init-sheet-data size)
+ (let (
+ (sheet-w 0)
+ (sheet-h 0)
+ (thumb-w 0)
+ (thumb-h 0)
+ (border-x 0) ;Space between rows and at top and bottom of thumbnails
+ (border-y 0) ;Space between columns and at left and right of thumbnails
+ (off-x 0) ; Additional X shift to properly center a row of thumbnails
+ (off-y 0) ; Additional Y shift to properly center rows of thumbnails
+ (count 0)
+ )
+
+ (case size
+ ((0) (set! sheet-w 640)
+ (set! sheet-h 480)
+ (set! thumb-w 90)
+ (set! thumb-h 68)
+ (set! border-x 32)
+ (set! border-y 23)
+ (set! off-x -1)
+ (set! off-y 0)
+ (set! count 4)
+ )
+
+ ((1) (set! sheet-w 800)
+ (set! sheet-h 600)
+ (set! thumb-w 119)
+ (set! thumb-h 90)
+ (set! border-x 34)
+ (set! border-y 25)
+ (set! off-x 0)
+ (set! off-y 0)
+ (set! count 4)
+ )
+
+ ((2) (set! sheet-w 1024)
+ (set! sheet-h 768)
+ (set! thumb-w 133)
+ (set! thumb-h 100)
+ (set! border-x 32)
+ (set! border-y 24)
+ (set! off-x 1)
+ (set! off-y 0)
+ (set! count 5)
+ )
+
+ ((3) (set! sheet-w 1280)
+ (set! sheet-h 1024)
+ (set! thumb-w 133)
+ (set! thumb-h 100)
+ (set! border-x 24)
+ (set! border-y 25)
+ (set! off-x 0)
+ (set! off-y 0)
+ (set! count 7)
+ )
+
+ ((4) (set! sheet-w 1600)
+ (set! sheet-h 1200)
+ (set! thumb-w 120)
+ (set! thumb-h 90)
+ (set! border-x 36)
+ (set! border-y 25)
+ (set! off-x 2)
+ (set! off-y 0)
+ (set! count 9)
+ )
+ )
+
+ (list sheet-w sheet-h thumb-w thumb-h border-x border-y off-x off-y count)
+ )
+ )
+
+ (define (init-sheet-img img num img-width border-y off-y)
+ (let* (
+ (text-layer 0)
+ (text-width 0)
+ (text-height 0)
+ )
+ (gimp-selection-all img)
+ (gimp-drawable-fill (car (gimp-image-get-active-layer img))
+ FILL-BACKGROUND)
+ (gimp-selection-none img)
+ (set! text-layer (car (gimp-text-fontname img -1 0 0
+ (string-append _"Contact Sheet "
+ (number->string num)
+ _" for directory " dir)
+ 0 TRUE 14 PIXELS title-font)))
+ (set! text-width (car (gimp-drawable-width text-layer)))
+ (set! text-height (car (gimp-drawable-height text-layer)))
+ (gimp-layer-set-offsets text-layer
+ (/ (- img-width text-width) 2)
+ (/ (- (+ border-y off-y) text-height) 2)
+ )
+ (gimp-image-merge-visible-layers img CLIP-TO-IMAGE)
+ )
+ )
+
+ (define (make-thumbnail-size img thumb-w thumb-h)
+ (let* (
+ (file-height (car (gimp-image-height img)))
+ (file-width (car (gimp-image-width img)))
+ (aspect-ratio (/ file-width file-height))
+ )
+
+ ;Preserve the aspect ratio of the original image
+ (if (> file-width file-height)
+ (set! thumb-h (/ thumb-w aspect-ratio))
+ (set! thumb-w (* thumb-h aspect-ratio))
+ )
+
+ (gimp-image-scale img thumb-w thumb-h)
+ )
+ )
+
+ (let* (
+ (dir-stream (dir-open-stream dir))
+ (sheet-num 1)
+ (img-count 0)
+ (pos-x 0)
+ (pos-y 0)
+
+ (sheet-data 0)
+ (sheet-width 0)
+ (sheet-height 0)
+ (thumb-w 0)
+ (thumb-h 0)
+ (border-x 0)
+ (border-y 0)
+ (off-x 0)
+ (off-y 0)
+ (max-x 0)
+ (max-y 0)
+
+ (sheet-img 0)
+ (sheet-layer 0)
+
+ (new-img 0)
+ (file 0)
+ (file-path 0)
+ (tmp-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+ (gimp-context-set-foreground text-color)
+ (gimp-context-set-background bg-color)
+
+ (set! sheet-data (init-sheet-data sheet-size))
+ (set! sheet-width (car sheet-data))
+ (set! sheet-height (cadr sheet-data))
+ (set! sheet-data (cddr sheet-data))
+ (set! thumb-w (car sheet-data))
+ (set! thumb-h (cadr sheet-data))
+ (set! sheet-data (cddr sheet-data))
+ (set! border-x (car sheet-data))
+ (set! border-y (cadr sheet-data))
+ (set! sheet-data (cddr sheet-data))
+ (set! off-x (car sheet-data))
+ (set! off-y (cadr sheet-data))
+ (set! max-x (caddr sheet-data))
+ (set! max-y max-x)
+
+ (set! sheet-img (car (gimp-image-new sheet-width sheet-height RGB)))
+
+ (gimp-image-undo-disable sheet-img)
+
+ (set! sheet-layer (car (gimp-layer-new sheet-img sheet-width sheet-height
+ RGB-IMAGE "Background"
+ 100 LAYER-MODE-NORMAL)))
+ (gimp-image-insert-layer sheet-img sheet-layer 0 0)
+
+ (init-sheet-img sheet-img sheet-num sheet-width border-y off-y)
+
+ (if (not dir-stream)
+ (gimp-message (string-append _"Unable to open directory " dir))
+ (begin
+ (do
+ ( (file (dir-read-entry dir-stream) (dir-read-entry dir-stream)) )
+ ( (eof-object? file) )
+
+ (set! file-path (string-append dir DIR-SEPARATOR file))
+ (if (and (not (re-match "index.*" file))
+ (= (file-type file-path) FILE-TYPE-FILE)
+ )
+ (catch ()
+ (set! new-img
+ (car (gimp-file-load RUN-NONINTERACTIVE file-path file)))
+
+ (make-thumbnail-size new-img thumb-w thumb-h)
+
+ (if (> (car (gimp-image-get-layers new-img)) 1)
+ (gimp-image-flatten new-img)
+ )
+ (set! tmp-layer (car (gimp-layer-new-from-drawable
+ (car (gimp-image-get-active-drawable new-img))
+ sheet-img)))
+
+ (gimp-image-insert-layer sheet-img tmp-layer 0 0)
+
+ ;Move thumbnail in to position and center it in area available.
+ (gimp-layer-set-offsets tmp-layer
+ (+ border-x off-x (* pos-x (+ thumb-w border-x))
+ (/ (- thumb-w (car (gimp-image-width new-img))) 2)
+ )
+ (+ border-y off-y (* pos-y (+ thumb-h border-y))
+ (/ (- thumb-h (car (gimp-image-height new-img))) 2)
+ )
+ )
+
+ (gimp-image-delete new-img)
+
+ (set! tmp-layer (car (gimp-text-fontname sheet-img -1 0 0 file
+ 0 TRUE 12 PIXELS legend-font)))
+ (gimp-layer-set-offsets tmp-layer
+ (+ border-x off-x (* pos-x (+ thumb-w border-x))
+ (/ (- thumb-w (car (gimp-drawable-width tmp-layer))) 2))
+ (+ border-y off-y (* pos-y (+ thumb-h border-y)) thumb-h 6)
+ )
+
+ (set! img-count (+ img-count 1))
+
+ (set! pos-x (+ pos-x 1))
+ (if (> pos-x max-x)
+ (begin
+ (set! pos-x 0)
+ (set! pos-y (+ pos-y 1))
+ (if (> pos-y max-y)
+ (begin
+ (set! pos-y 0)
+ (set! sheet-layer (car (gimp-image-flatten sheet-img)))
+ (gimp-file-save
+ RUN-NONINTERACTIVE
+ sheet-img
+ sheet-layer
+ (string-append dir DIR-SEPARATOR
+ "index" (number->string sheet-num) ".jpg")
+ (string-append
+ "index" (number->string sheet-num) ".jpg")
+ )
+
+ (set! sheet-num (+ sheet-num 1))
+ (init-sheet-img sheet-img sheet-num sheet-width
+ border-y off-y)
+ (set! img-count 0)
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+
+ (dir-close-stream dir-stream)
+
+ (if (> img-count 0)
+ (begin
+ (set! sheet-layer (car (gimp-image-flatten sheet-img)))
+ (gimp-file-save
+ RUN-NONINTERACTIVE
+ sheet-img
+ sheet-layer
+ (string-append dir DIR-SEPARATOR
+ "index" (number->string sheet-num) ".jpg")
+ (string-append "index" (number->string sheet-num) ".jpg")
+ )
+ )
+ )
+ )
+
+ (gimp-image-undo-enable sheet-img)
+ (gimp-image-delete sheet-img)
+
+ (display (string-append _"Created " (number->string sheet-num)
+ _" contact sheets from a total of "
+ (number->string img-count) _" images"))
+ (newline)
+ )
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-contactsheet"
+ _"_Contact Sheet..."
+ _"Create a series of images containing thumbnail sized versions of all of the images in a specified directory."
+ "Kevin Cozens <kcozens@interlog.com>"
+ "Kevin Cozens"
+ "July 19, 2004"
+ ""
+ SF-DIRNAME _"Images Directory" "/tmp/test"
+ SF-OPTION _"Sheet size" '("640 x 480"
+ "800 x 600"
+ "1024 x 768"
+ "1280 x 1024"
+ "1600 x 1200")
+ SF-FONT _"Title font" "Sans Bold Italic"
+ SF-FONT _"Legend font" "Sans Bold"
+ SF-COLOR _"Text color" "white"
+ SF-COLOR _"Background color" "black"
+)
+
+(script-fu-menu-register "script-fu-contactsheet" "<Image>/Filters/Combine")
diff --git a/plug-ins/script-fu/scripts/copy-visible.scm b/plug-ins/script-fu/scripts/copy-visible.scm
new file mode 100644
index 0000000..942793c
--- /dev/null
+++ b/plug-ins/script-fu/scripts/copy-visible.scm
@@ -0,0 +1,49 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; "Copy Visible" -- copy the visible selection so that it can be pasted easily
+; Copyright (C) 2004 Raphaël Quinet, Adrian Likins, Sven Neumann
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; 2004-04-14 This script was almost rewritten from scratch
+; by Raphaël Quinet <raphael@gimp.org>
+; see also http://bugzilla.gnome.org/show_bug.cgi?id=139989
+;
+; The code is new but the API is the same as in the previous version:
+; "Copy Visible" version 0.11 01/24/98
+; by Adrian Likins <adrian@gimp.org>
+; _heavily_ based on:
+; cyn-merge.scm version 0.02 10/10/97
+; Copyright (C) 1997 Sven Neumann (neumanns@uni-duesseldorf.de)
+;
+; Removed all code and made it a backward-compat wrapper around
+; (gimp-edit-copy-visible)
+; 2004-12-12 Michael Natterer <mitch@gimp.org>
+;
+
+(define (script-fu-copy-visible image drawable)
+ (gimp-edit-copy-visible image)
+)
+
+(script-fu-register "script-fu-copy-visible"
+ "Copy Visible"
+ "This procedure is deprecated! Use \'gimp-edit-copy-visible\' instead."
+ ""
+ ""
+ ""
+ "RGB* INDEXED* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+)
diff --git a/plug-ins/script-fu/scripts/difference-clouds.scm b/plug-ins/script-fu/scripts/difference-clouds.scm
new file mode 100644
index 0000000..15b8fc8
--- /dev/null
+++ b/plug-ins/script-fu/scripts/difference-clouds.scm
@@ -0,0 +1,80 @@
+; Plugin for the GNU Image Manipulation Program
+; Copyright (C) 2006 Martin Nordholts
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Renders Difference Clouds onto a layer, i.e. solid noise merged down with the
+; Difference Mode
+;
+
+(define (script-fu-difference-clouds image
+ drawable)
+
+ (let* ((draw-offset-x (car (gimp-drawable-offsets drawable)))
+ (draw-offset-y (cadr (gimp-drawable-offsets drawable)))
+ (has-sel (car (gimp-drawable-mask-intersect drawable)))
+ (sel-offset-x (cadr (gimp-drawable-mask-intersect drawable)))
+ (sel-offset-y (caddr (gimp-drawable-mask-intersect drawable)))
+ (width (cadddr (gimp-drawable-mask-intersect drawable)))
+ (height (caddr (cddr (gimp-drawable-mask-intersect drawable))))
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (diff-clouds -1)
+ (offset-x 0)
+ (offset-y 0)
+ )
+
+ (gimp-image-undo-group-start image)
+
+ ; Create the cloud layer
+ (set! diff-clouds (car (gimp-layer-new image width height type
+ "Clouds" 100 LAYER-MODE-DIFFERENCE)))
+
+ ; Add the cloud layer above the current layer
+ (gimp-image-insert-layer image diff-clouds 0 -1)
+
+ ; Clear the layer (so there are no noise in it)
+ (gimp-drawable-fill diff-clouds FILL-TRANSPARENT)
+
+ ; Selections are relative to the drawable; adjust the final offset
+ (set! offset-x (+ draw-offset-x sel-offset-x))
+ (set! offset-y (+ draw-offset-y sel-offset-y))
+
+ ; Offset the clouds layer
+ (if (gimp-item-is-layer drawable)
+ (gimp-item-transform-translate diff-clouds offset-x offset-y))
+
+ ; Show the solid noise dialog
+ (plug-in-solid-noise SF-RUN-MODE image diff-clouds 0 0 0 1 4.0 4.0)
+
+ ; Merge the clouds layer with the layer below
+ (gimp-image-merge-down image diff-clouds EXPAND-AS-NECESSARY)
+
+ (gimp-image-undo-group-end image)
+
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-difference-clouds"
+ _"_Difference Clouds..."
+ _"Solid noise applied with Difference layer mode"
+ "Martin Nordholts <enselic@hotmail.com>"
+ "Martin Nordholts"
+ "2006/10/25"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0)
+
+(script-fu-menu-register "script-fu-difference-clouds"
+ "<Image>/Filters/Render/Noise")
diff --git a/plug-ins/script-fu/scripts/distress-selection.scm b/plug-ins/script-fu/scripts/distress-selection.scm
new file mode 100644
index 0000000..ef87b79
--- /dev/null
+++ b/plug-ins/script-fu/scripts/distress-selection.scm
@@ -0,0 +1,122 @@
+;
+; distress selection
+;
+;
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+; Define the function:
+
+(define (script-fu-distress-selection inImage
+ inDrawable
+ inThreshold
+ inSpread
+ inGranu
+ inSmooth
+ inSmoothH
+ inSmoothV)
+
+ (let (
+ (theImage inImage)
+ (theWidth (car (gimp-image-width inImage)))
+ (theHeight (car (gimp-image-height inImage)))
+ (theLayer 0)
+ (theMode (car (gimp-image-base-type inImage)))
+ (prevLayer (car (gimp-image-get-active-layer inImage)))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+ (gimp-image-undo-group-start theImage)
+
+ (if (= theMode GRAY)
+ (set! theMode GRAYA-IMAGE)
+ (set! theMode RGBA-IMAGE)
+ )
+ (set! theLayer (car (gimp-layer-new theImage
+ theWidth
+ theHeight
+ theMode
+ "Distress Scratch Layer"
+ 100
+ LAYER-MODE-NORMAL)))
+
+ (gimp-image-insert-layer theImage theLayer 0 0)
+
+ (if (= FALSE (car (gimp-selection-is-empty theImage)))
+ (gimp-drawable-edit-fill theLayer FILL-BACKGROUND)
+ )
+
+ (gimp-selection-invert theImage)
+
+ (if (= FALSE (car (gimp-selection-is-empty theImage)))
+ (gimp-drawable-edit-clear theLayer)
+ )
+
+ (gimp-selection-invert theImage)
+ (gimp-selection-none inImage)
+
+ (gimp-layer-scale theLayer
+ (/ theWidth inGranu)
+ (/ theHeight inGranu)
+ TRUE)
+
+ (plug-in-spread RUN-NONINTERACTIVE
+ theImage
+ theLayer
+ inSpread
+ inSpread)
+
+ (plug-in-gauss-iir RUN-NONINTERACTIVE
+ theImage theLayer inSmooth inSmoothH inSmoothV)
+ (gimp-layer-scale theLayer theWidth theHeight TRUE)
+ (plug-in-threshold-alpha RUN-NONINTERACTIVE theImage theLayer inThreshold)
+ (plug-in-gauss-iir RUN-NONINTERACTIVE theImage theLayer 1 TRUE TRUE)
+ (gimp-image-select-item inImage CHANNEL-OP-REPLACE theLayer)
+ (gimp-image-remove-layer theImage theLayer)
+ (if (and (= (car (gimp-item-is-channel inDrawable)) TRUE)
+ (= (car (gimp-item-is-layer-mask inDrawable)) FALSE))
+ (gimp-image-set-active-channel theImage inDrawable)
+ )
+ (gimp-image-undo-group-end theImage)
+
+ (gimp-image-set-active-layer theImage prevLayer)
+
+ (gimp-displays-flush)
+ (gimp-context-pop)
+ )
+)
+
+
+(script-fu-register "script-fu-distress-selection"
+ _"_Distort..."
+ _"Distress the selection"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "23rd April 1998"
+ "RGB*,GRAY*"
+ SF-IMAGE "The image" 0
+ SF-DRAWABLE "The layer" 0
+ SF-ADJUSTMENT _"_Threshold (bigger 1<-->254 smaller)" '(127 1 254 1 10 0 0)
+ SF-ADJUSTMENT _"_Spread" '(8 0 1000 1 10 0 1)
+ SF-ADJUSTMENT _"_Granularity (1 is low)" '(4 1 25 1 10 0 1)
+ SF-ADJUSTMENT _"S_mooth" '(2 1 150 1 10 0 1)
+ SF-TOGGLE _"Smooth hor_izontally" TRUE
+ SF-TOGGLE _"Smooth _vertically" TRUE
+)
+
+(script-fu-menu-register "script-fu-distress-selection"
+ "<Image>/Select/Modify")
diff --git a/plug-ins/script-fu/scripts/drop-shadow.scm b/plug-ins/script-fu/scripts/drop-shadow.scm
new file mode 100644
index 0000000..c1b243a
--- /dev/null
+++ b/plug-ins/script-fu/scripts/drop-shadow.scm
@@ -0,0 +1,187 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; drop-shadow.scm version 1.05 2011/4/21
+;
+; CHANGE-LOG:
+; 1.00 - initial release
+; 1.01 - fixed the problem with a remaining copy of the selection
+; 1.02 - some code cleanup, no real changes
+; 1.03 - can't call gimp-drawable-edit-fill until layer is added to image!
+; 1.04
+; 1.05 - replaced deprecated function calls with new ones for 2.8
+;
+; Copyright (C) 1997-1999 Sven Neumann <sven@gimp.org>
+;
+;
+; Adds a drop-shadow of the current selection or alpha-channel.
+;
+; This script is derived from my script add-shadow, which has become
+; obsolete now. Thanks to Andrew Donkin (ard@cs.waikato.ac.nz) for his
+; idea to add alpha-support to add-shadow.
+
+
+(define (script-fu-drop-shadow image
+ drawable
+ shadow-transl-x
+ shadow-transl-y
+ shadow-blur
+ shadow-color
+ shadow-opacity
+ allow-resize)
+ (let* (
+ (shadow-blur (max shadow-blur 0))
+ (shadow-opacity (min shadow-opacity 100))
+ (shadow-opacity (max shadow-opacity 0))
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (image-height (car (gimp-image-height image)))
+ (from-selection 0)
+ (active-selection 0)
+ (shadow-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-set-active-layer image drawable)
+
+ (gimp-image-undo-group-start image)
+
+ (gimp-layer-add-alpha drawable)
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! from-selection FALSE))
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))))
+
+ (let* ((selection-bounds (gimp-selection-bounds image))
+ (select-offset-x (cadr selection-bounds))
+ (select-offset-y (caddr selection-bounds))
+ (select-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (select-height (- (caddr (cddr selection-bounds)) select-offset-y))
+
+ (shadow-width (+ select-width (* 2 shadow-blur)))
+ (shadow-height (+ select-height (* 2 shadow-blur)))
+
+ (shadow-offset-x (- select-offset-x shadow-blur))
+ (shadow-offset-y (- select-offset-y shadow-blur)))
+
+ (if (= allow-resize TRUE)
+ (let* ((new-image-width image-width)
+ (new-image-height image-height)
+ (image-offset-x 0)
+ (image-offset-y 0))
+
+ (if (< (+ shadow-offset-x shadow-transl-x) 0)
+ (begin
+ (set! image-offset-x (- 0 (+ shadow-offset-x
+ shadow-transl-x)))
+ (set! shadow-offset-x (- 0 shadow-transl-x))
+ (set! new-image-width (+ new-image-width image-offset-x))))
+
+ (if (< (+ shadow-offset-y shadow-transl-y) 0)
+ (begin
+ (set! image-offset-y (- 0 (+ shadow-offset-y
+ shadow-transl-y)))
+ (set! shadow-offset-y (- 0 shadow-transl-y))
+ (set! new-image-height (+ new-image-height image-offset-y))))
+
+ (if (> (+ (+ shadow-width shadow-offset-x) shadow-transl-x)
+ new-image-width)
+ (set! new-image-width
+ (+ (+ shadow-width shadow-offset-x) shadow-transl-x)))
+
+ (if (> (+ (+ shadow-height shadow-offset-y) shadow-transl-y)
+ new-image-height)
+ (set! new-image-height
+ (+ (+ shadow-height shadow-offset-y) shadow-transl-y)))
+
+ (gimp-image-resize image
+ new-image-width
+ new-image-height
+ image-offset-x
+ image-offset-y)
+ )
+ )
+
+ (set! shadow-layer (car (gimp-layer-new image
+ shadow-width
+ shadow-height
+ type
+ "Drop Shadow"
+ shadow-opacity
+ LAYER-MODE-NORMAL)))
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-insert-layer image shadow-layer 0 -1)
+ (gimp-layer-set-offsets shadow-layer
+ shadow-offset-x
+ shadow-offset-y))
+
+ (gimp-drawable-fill shadow-layer FILL-TRANSPARENT)
+ (gimp-context-set-background shadow-color)
+ (gimp-drawable-edit-fill shadow-layer FILL-BACKGROUND)
+ (gimp-selection-none image)
+ (gimp-layer-set-lock-alpha shadow-layer FALSE)
+ (if (>= shadow-blur 1.0) (plug-in-gauss-rle RUN-NONINTERACTIVE
+ image
+ shadow-layer
+ shadow-blur
+ TRUE
+ TRUE))
+ (gimp-item-transform-translate shadow-layer shadow-transl-x shadow-transl-y)
+
+ (if (= from-selection TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-drawable-edit-clear shadow-layer)
+ (gimp-image-remove-channel image active-selection)))
+
+ (if (and
+ (= (car (gimp-layer-is-floating-sel drawable)) 0)
+ (= from-selection FALSE))
+ (gimp-image-raise-item image drawable))
+
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-drop-shadow"
+ _"_Drop Shadow (legacy)..."
+ _"Add a drop shadow to the selected region (or alpha)"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "1999/12/21"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Offset X" '(4 -4096 4096 1 10 0 1)
+ SF-ADJUSTMENT _"Offset Y" '(4 -4096 4096 1 10 0 1)
+ SF-ADJUSTMENT _"Blur radius" '(15 0 1024 1 10 0 1)
+ SF-COLOR _"Color" "black"
+ SF-ADJUSTMENT _"Opacity" '(60 0 100 1 10 0 0)
+ SF-TOGGLE _"Allow resizing" TRUE
+)
+
+(script-fu-menu-register "script-fu-drop-shadow"
+ "<Image>/Filters/Light and Shadow/Shadow")
diff --git a/plug-ins/script-fu/scripts/erase-rows.scm b/plug-ins/script-fu/scripts/erase-rows.scm
new file mode 100644
index 0000000..4ae4c77
--- /dev/null
+++ b/plug-ins/script-fu/scripts/erase-rows.scm
@@ -0,0 +1,71 @@
+(define (script-fu-erase-rows img drawable orientation which type)
+ (script-fu-erase-nth-rows img drawable orientation which type 2)
+)
+
+(define (script-fu-erase-nth-rows img drawable orientation offset type nth)
+ (let* (
+ (width (car (gimp-drawable-width drawable)))
+ (height (car (gimp-drawable-height drawable)))
+ (position-x (car (gimp-drawable-offsets drawable)))
+ (position-y (cadr (gimp-drawable-offsets drawable)))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+ (gimp-context-set-feather FALSE)
+ (gimp-image-undo-group-start img)
+ (letrec ((loop (lambda (i max)
+ (if (< i max)
+ (begin
+ (if (= orientation 0)
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE position-x (+ i position-y) width 1)
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE (+ i position-x) position-y 1 height))
+ (if (= type 0)
+ (gimp-drawable-edit-clear drawable)
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND))
+ (loop (+ i nth) max))))))
+ (loop offset
+ (if (= orientation 0)
+ height
+ width)
+ )
+ )
+ (gimp-selection-none img)
+ (gimp-image-undo-group-end img)
+ (gimp-context-pop)
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-erase-nth-rows"
+ _"_Erase Every Nth Row..."
+ _"Erase every nth row or column"
+ "Federico Mena Quintero, Nikc M. (Altered)"
+ "Federico Mena Quintero"
+ "June 1997, February 2020"
+ "RGB* GRAY* INDEXED*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-OPTION _"Rows/cols" '(_"Rows" _"Columns")
+ SF-ADJUSTMENT "Offset" '(0 0 1024 1 10 0 SF-SPINNER)
+ SF-OPTION _"Erase/fill" '(_"Erase" _"Fill with BG")
+ SF-ADJUSTMENT "Skip by" '(1 1 1024 1 10 0 SF-SPINNER)
+)
+
+(script-fu-register "script-fu-erase-rows"
+ _"_Erase Every Other Row..."
+ _"Erase every other row or column"
+ "Federico Mena Quintero"
+ "Federico Mena Quintero"
+ "June 1997"
+ "RGB* GRAY* INDEXED*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-OPTION _"Rows/cols" '(_"Rows" _"Columns")
+ SF-OPTION _"Even/odd" '(_"Even" _"Odd")
+ SF-OPTION _"Erase/fill" '(_"Erase" _"Fill with BG")
+)
+
+; (script-fu-menu-register "script-fu-erase-rows"
+; "<Image>/Filters/Distorts")
diff --git a/plug-ins/script-fu/scripts/font-map.scm b/plug-ins/script-fu/scripts/font-map.scm
new file mode 100644
index 0000000..7481d28
--- /dev/null
+++ b/plug-ins/script-fu/scripts/font-map.scm
@@ -0,0 +1,168 @@
+;; font-select
+;; Spencer Kimball
+
+(define (script-fu-font-map text
+ use-name
+ labels
+ font-filter
+ font-size
+ border
+ colors)
+
+ (define (max-font-width text use-name list-cnt list font-size)
+ (let* ((count 0)
+ (width 0)
+ (maxwidth 0)
+ (font "")
+ (extents '()))
+ (while (< count list-cnt)
+ (set! font (car list))
+
+ (if (= use-name TRUE)
+ (set! text font))
+ (set! extents (gimp-text-get-extents-fontname text
+ font-size PIXELS
+ font))
+ (set! width (car extents))
+ (if (> width maxwidth)
+ (set! maxwidth width))
+
+ (set! list (cdr list))
+ (set! count (+ count 1))
+ )
+
+ maxwidth
+ )
+ )
+
+ (define (max-font-height text use-name list-cnt list font-size)
+ (let* ((count 0)
+ (height 0)
+ (maxheight 0)
+ (font "")
+ (extents '()))
+ (while (< count list-cnt)
+ (set! font (car list))
+
+ (if (= use-name TRUE)
+ (set! text font)
+ )
+ (set! extents (gimp-text-get-extents-fontname text
+ font-size PIXELS
+ font))
+ (set! height (cadr extents))
+ (if (> height maxheight)
+ (set! maxheight height)
+ )
+
+ (set! list (cdr list))
+ (set! count (+ count 1))
+ )
+
+ maxheight
+ )
+ )
+
+ (let* (
+ (font-data (gimp-fonts-get-list font-filter))
+ (font-list (cadr font-data))
+ (num-fonts (car font-data))
+ (label-size (/ font-size 2))
+ (border (+ border (* labels (/ label-size 2))))
+ (y border)
+ (maxheight (max-font-height text use-name num-fonts font-list font-size))
+ (maxwidth (max-font-width text use-name num-fonts font-list font-size))
+ (width (+ maxwidth (* 2 border)))
+ (height (+ (+ (* maxheight num-fonts) (* 2 border))
+ (* labels (* label-size num-fonts))))
+ (img (car (gimp-image-new width height (if (= colors 0)
+ GRAY RGB))))
+ (drawable (car (gimp-layer-new img width height (if (= colors 0)
+ GRAY-IMAGE RGB-IMAGE)
+ "Background" 100 LAYER-MODE-NORMAL)))
+ (count 0)
+ (font "")
+ )
+
+ (gimp-context-push)
+
+ (gimp-image-undo-disable img)
+
+ (if (= colors 0)
+ (begin
+ (gimp-context-set-background '(255 255 255))
+ (gimp-context-set-foreground '(0 0 0))))
+
+ (gimp-image-insert-layer img drawable 0 0)
+ (gimp-drawable-edit-clear drawable)
+
+ (if (= labels TRUE)
+ (begin
+ (set! drawable (car (gimp-layer-new img width height
+ (if (= colors 0)
+ GRAYA-IMAGE RGBA-IMAGE)
+ "Labels" 100 LAYER-MODE-NORMAL)))
+ (gimp-image-insert-layer img drawable 0 -1)))
+ (gimp-drawable-edit-clear drawable)
+
+ (while (< count num-fonts)
+ (set! font (car font-list))
+
+ (if (= use-name TRUE)
+ (set! text font))
+
+ (gimp-text-fontname img -1
+ border
+ y
+ text
+ 0 TRUE font-size PIXELS
+ font)
+
+ (set! y (+ y maxheight))
+
+ (if (= labels TRUE)
+ (begin
+ (gimp-floating-sel-anchor (car (gimp-text-fontname img drawable
+ (- border
+ (/ label-size 2))
+ (- y
+ (/ label-size 2))
+ font
+ 0 TRUE
+ label-size PIXELS
+ "Sans")))
+ (set! y (+ y label-size))
+ )
+ )
+
+ (set! font-list (cdr font-list))
+ (set! count (+ count 1))
+ )
+
+ (gimp-image-set-active-layer img drawable)
+
+ (gimp-image-undo-enable img)
+ (gimp-display-new img)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-font-map"
+ _"Render _Font Map..."
+ _"Create an image filled with previews of fonts matching a fontname filter"
+ "Spencer Kimball"
+ "Spencer Kimball"
+ "1997"
+ ""
+ SF-STRING _"_Text" "How quickly daft jumping zebras vex."
+ SF-TOGGLE _"Use font _name as text" FALSE
+ SF-TOGGLE _"_Labels" TRUE
+ SF-STRING _"_Filter (regexp)" "Sans"
+ SF-ADJUSTMENT _"Font _size (pixels)" '(32 2 1000 1 10 0 1)
+ SF-ADJUSTMENT _"_Border (pixels)" '(10 0 200 1 10 0 1)
+ SF-OPTION _"_Color scheme" '(_"Black on white" _"Active colors")
+)
+
+(script-fu-menu-register "script-fu-font-map"
+ "<Fonts>")
diff --git a/plug-ins/script-fu/scripts/fuzzyborder.scm b/plug-ins/script-fu/scripts/fuzzyborder.scm
new file mode 100644
index 0000000..9c3ddbe
--- /dev/null
+++ b/plug-ins/script-fu/scripts/fuzzyborder.scm
@@ -0,0 +1,168 @@
+;
+; fuzzy-border
+;
+; Do a cool fade to a given color at the border of an image (optional shadow)
+; Will make image RGB if it isn't already.
+;
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+; Define the function:
+
+(define (script-fu-fuzzy-border inImage
+ inLayer
+ inColor
+ inSize
+ inBlur
+ inGranu
+ inShadow
+ inShadWeight
+ inCopy
+ inFlatten
+ )
+
+ (define (chris-color-edge inImage inLayer inColor inSize)
+ (gimp-selection-all inImage)
+ (gimp-selection-shrink inImage inSize)
+ (gimp-selection-invert inImage)
+ (gimp-context-set-background inColor)
+ (gimp-drawable-edit-fill inLayer FILL-BACKGROUND)
+ (gimp-selection-none inImage)
+ )
+
+ (let (
+ (theWidth (car (gimp-image-width inImage)))
+ (theHeight (car (gimp-image-height inImage)))
+ (theImage (if (= inCopy TRUE) (car (gimp-image-duplicate inImage))
+ inImage))
+ (theLayer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (if (= inCopy TRUE)
+ (gimp-image-undo-disable theImage)
+ (gimp-image-undo-group-start theImage)
+ )
+
+ (gimp-selection-all theImage)
+
+ (if (> (car (gimp-drawable-type inLayer)) 1)
+ (gimp-image-convert-rgb theImage)
+ )
+
+ (set! theLayer (car (gimp-layer-new theImage
+ theWidth
+ theHeight
+ RGBA-IMAGE
+ "layer 1"
+ 100
+ LAYER-MODE-NORMAL)))
+
+ (gimp-image-insert-layer theImage theLayer 0 0)
+
+
+ (gimp-drawable-edit-clear theLayer)
+ (chris-color-edge theImage theLayer inColor inSize)
+
+ (gimp-layer-scale theLayer
+ (/ theWidth inGranu)
+ (/ theHeight inGranu)
+ TRUE)
+
+ (plug-in-spread RUN-NONINTERACTIVE
+ theImage
+ theLayer
+ (/ inSize inGranu)
+ (/ inSize inGranu))
+ (chris-color-edge theImage theLayer inColor 1)
+ (gimp-layer-scale theLayer theWidth theHeight TRUE)
+
+ (gimp-image-select-item theImage CHANNEL-OP-REPLACE theLayer)
+ (gimp-selection-invert theImage)
+ (gimp-drawable-edit-clear theLayer)
+ (gimp-selection-invert theImage)
+ (gimp-drawable-edit-clear theLayer)
+ (gimp-context-set-background inColor)
+ (gimp-drawable-edit-fill theLayer FILL-BACKGROUND)
+ (gimp-selection-none theImage)
+ (chris-color-edge theImage theLayer inColor 1)
+
+ (if (= inBlur TRUE)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ theImage theLayer inSize TRUE TRUE)
+ )
+ (if (= inShadow TRUE)
+ (begin
+ (gimp-image-insert-layer theImage
+ (car (gimp-layer-copy theLayer FALSE)) 0 -1)
+ (gimp-layer-scale theLayer
+ (- theWidth inSize) (- theHeight inSize) TRUE)
+ (gimp-drawable-desaturate theLayer DESATURATE-LIGHTNESS)
+ (gimp-drawable-brightness-contrast theLayer 0.5 0.5)
+ (gimp-drawable-invert theLayer FALSE)
+ (gimp-layer-resize theLayer
+ theWidth
+ theHeight
+ (/ inSize 2)
+ (/ inSize 2))
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ theImage
+ theLayer
+ (/ inSize 2)
+ TRUE
+ TRUE)
+ (gimp-layer-set-opacity theLayer inShadWeight)
+ )
+ )
+ (if (= inFlatten TRUE)
+ (gimp-image-flatten theImage)
+ )
+ (if (= inCopy TRUE)
+ (begin (gimp-image-clean-all theImage)
+ (gimp-display-new theImage)
+ (gimp-image-undo-enable theImage)
+ )
+ (gimp-image-undo-group-end theImage)
+ )
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-fuzzy-border"
+ _"_Fuzzy Border..."
+ _"Add a jagged, fuzzy border to an image"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "3rd April 1998"
+ "RGB* GRAY*"
+ SF-IMAGE "The image" 0
+ SF-DRAWABLE "The layer" 0
+ SF-COLOR _"Color" "white"
+ SF-ADJUSTMENT _"Border size" '(16 1 300 1 10 0 1)
+ SF-TOGGLE _"Blur border" TRUE
+ SF-ADJUSTMENT _"Granularity (1 is Low)" '(4 1 16 0.25 5 2 0)
+ SF-TOGGLE _"Add shadow" FALSE
+ SF-ADJUSTMENT _"Shadow weight (%)" '(100 0 100 1 10 0 0)
+ SF-TOGGLE _"Work on copy" TRUE
+ SF-TOGGLE _"Flatten image" TRUE
+)
+
+(script-fu-menu-register "script-fu-fuzzy-border"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/gimp-online.scm b/plug-ins/script-fu/scripts/gimp-online.scm
new file mode 100644
index 0000000..69afd10
--- /dev/null
+++ b/plug-ins/script-fu/scripts/gimp-online.scm
@@ -0,0 +1,293 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; gimp-online.scm
+; Copyright (C) 2003 Henrik Brix Andersen <brix@gimp.org>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define (gimp-online-docs-web-site)
+ (plug-in-web-browser "https://docs.gimp.org/")
+)
+
+(define (gimp-help-main)
+ (gimp-help "" "gimp-main")
+)
+
+(define (gimp-help-concepts-usage)
+ (gimp-help "" "gimp-concepts-usage")
+)
+
+(define (gimp-help-using-docks)
+ (gimp-help "" "gimp-concepts-docks")
+)
+
+(define (gimp-help-using-simpleobjects)
+ (gimp-help "" "gimp-using-simpleobjects")
+)
+
+(define (gimp-help-using-selections)
+ (gimp-help "" "gimp-using-selections")
+)
+
+(define (gimp-help-using-fileformats)
+ (gimp-help "" "gimp-using-fileformats")
+)
+
+(define (gimp-help-using-photography)
+ (gimp-help "" "gimp-using-photography")
+)
+
+(define (gimp-help-using-web)
+ (gimp-help "" "gimp-using-web")
+)
+
+(define (gimp-help-concepts-paths)
+ (gimp-help "" "gimp-concepts-paths")
+)
+
+
+; shortcuts to help topics
+(script-fu-register "gimp-help-concepts-paths"
+ _"Using _Paths"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-concepts-paths"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-web"
+ _"_Preparing your Images for the Web"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-web"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-photography"
+ _"_Working with Digital Camera Photos"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-photography"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-fileformats"
+ _"Create, Open and Save _Files"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-fileformats"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-concepts-usage"
+ _"_Basic Concepts"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-concepts-usage"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-docks"
+ _"How to Use _Dialogs"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-docks"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-simpleobjects"
+ _"Drawing _Simple Objects"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-simpleobjects"
+ "<Image>/Help/User Manual")
+
+
+(script-fu-register "gimp-help-using-selections"
+ _"Create and Use _Selections"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-using-simpleobjects"
+ "<Image>/Help/User Manual")
+
+(script-fu-register "gimp-help-main"
+ _"_[Table of Contents]"
+ _"Bookmark to the user manual"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-help-main"
+ "<Image>/Help/User Manual")
+
+
+;; Links to GIMP related web sites
+
+(define (gimp-online-main-web-site)
+ (plug-in-web-browser "https://www.gimp.org/")
+)
+
+(define (gimp-online-developer-web-site)
+ (plug-in-web-browser "https://developer.gimp.org/")
+)
+
+(define (gimp-online-roadmap)
+ (plug-in-web-browser "https://wiki.gimp.org/wiki/Roadmap")
+)
+
+(define (gimp-online-wiki)
+ (plug-in-web-browser "https://wiki.gimp.org/wiki/Main_Page")
+)
+
+(define (gimp-online-bugs-features)
+ (plug-in-web-browser "https://gitlab.gnome.org/GNOME/gimp/issues")
+)
+
+; (define (gimp-online-plug-in-web-site)
+; (plug-in-web-browser "https://registry.gimp.org/")
+; )
+
+
+(script-fu-register "gimp-online-main-web-site"
+ _"_Main Web Site"
+ _"Bookmark to the GIMP web site"
+ "Henrik Brix Andersen <brix@gimp.org>"
+ "Henrik Brix Andersen <brix@gimp.org>"
+ "2003"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-main-web-site"
+ "<Image>/Help/GIMP Online")
+
+
+(script-fu-register "gimp-online-developer-web-site"
+ _"_Developer Web Site"
+ _"Bookmark to the GIMP web site"
+ "Henrik Brix Andersen <brix@gimp.org>"
+ "Henrik Brix Andersen <brix@gimp.org>"
+ "2003"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-developer-web-site"
+ "<Image>/Help/GIMP Online")
+
+
+(script-fu-register "gimp-online-roadmap"
+ _"_Roadmap"
+ _"Bookmark to the roadmap of GIMP"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "2018"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-roadmap"
+ "<Image>/Help/GIMP Online")
+
+
+(script-fu-register "gimp-online-wiki"
+ _"_Wiki"
+ _"Bookmark to the wiki of GIMP"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "2018"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-wiki"
+ "<Image>/Help/GIMP Online")
+
+
+(script-fu-register "gimp-online-bugs-features"
+ _"_Bug Reports and Feature Requests"
+ _"Bookmark to the bug tracker of GIMP"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>"
+ "2018"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-bugs-features"
+ "<Image>/Help")
+
+
+(script-fu-register "gimp-online-docs-web-site"
+ _"_User Manual Web Site"
+ _"Bookmark to the GIMP web site"
+ "Roman Joost <romanofski@gimp.org>"
+ "Roman Joost <romanofski@gimp.org>"
+ "2006"
+ ""
+)
+
+(script-fu-menu-register "gimp-online-docs-web-site"
+ "<Image>/Help/GIMP Online")
+
+
+; (script-fu-register "gimp-online-plug-in-web-site"
+; _"Plug-in _Registry"
+; _"Bookmark to the GIMP web site"
+; "Henrik Brix Andersen <brix@gimp.org>"
+; "Henrik Brix Andersen <brix@gimp.org>"
+; "2003"
+; ""
+; )
+
+; (script-fu-menu-register "gimp-online-plug-in-web-site"
+; "<Image>/Help/GIMP Online")
diff --git a/plug-ins/script-fu/scripts/gradient-example.scm b/plug-ins/script-fu/scripts/gradient-example.scm
new file mode 100644
index 0000000..3157c88
--- /dev/null
+++ b/plug-ins/script-fu/scripts/gradient-example.scm
@@ -0,0 +1,81 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Gradient example script --- create an example image of a custom gradient
+; Copyright (C) 1997 Federico Mena Quintero
+; federico@nuclecu.unam.mx
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define (script-fu-gradient-example width
+ height
+ gradient-reverse)
+ (let* (
+ (img (car (gimp-image-new width height RGB)))
+ (drawable (car (gimp-layer-new img width height RGB
+ "Gradient example" 100 LAYER-MODE-NORMAL)))
+
+ ; Calculate colors for checkerboard... just like in the gradient editor
+
+ (fg-color (* 255 (/ 2 3)))
+ (bg-color (* 255 (/ 1 3)))
+ )
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ ; Render background checkerboard
+
+ (gimp-context-push)
+
+ (gimp-context-set-foreground (list fg-color fg-color fg-color))
+ (gimp-context-set-background (list bg-color bg-color bg-color))
+ (plug-in-checkerboard RUN-NONINTERACTIVE img drawable 0 8)
+
+ (gimp-context-pop)
+
+ ; Render gradient
+
+ (gimp-context-push)
+
+ (gimp-context-set-gradient-reverse gradient-reverse)
+ (gimp-drawable-edit-gradient-fill drawable
+ GRADIENT-LINEAR 0
+ FALSE 0 0
+ TRUE
+ 0 0 (- width 1) 0)
+
+ (gimp-context-pop)
+
+ ; Terminate
+
+ (gimp-image-undo-enable img)
+ (gimp-display-new img)
+ )
+)
+
+(script-fu-register "script-fu-gradient-example"
+ _"Custom _Gradient..."
+ _"Create an image filled with an example of the current gradient"
+ "Federico Mena Quintero"
+ "Federico Mena Quintero"
+ "June 1997"
+ ""
+ SF-ADJUSTMENT _"Width" '(400 1 2000 1 10 0 1)
+ SF-ADJUSTMENT _"Height" '(30 1 2000 1 10 0 1)
+ SF-TOGGLE _"Gradient reverse" FALSE
+)
+
+(script-fu-menu-register "script-fu-gradient-example"
+ "<Gradients>")
diff --git a/plug-ins/script-fu/scripts/grid-system.scm b/plug-ins/script-fu/scripts/grid-system.scm
new file mode 100644
index 0000000..6607a3e
--- /dev/null
+++ b/plug-ins/script-fu/scripts/grid-system.scm
@@ -0,0 +1,95 @@
+;;; grid-system.scm -*-scheme-*-
+;;; Time-stamp: <1998/01/20 23:22:02 narazaki@InetQ.or.jp>
+;;; This file is a part of:
+;;; GIMP (Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis)
+;;; Author: Shuji Narazaki (narazaki@InetQ.or.jp)
+;;; Version 0.6
+
+;;; Code:
+(if (not (symbol-bound? 'script-fu-grid-system-x-divides (current-environment)))
+ (define script-fu-grid-system-x-divides "'(1 g 1)"))
+(if (not (symbol-bound? 'script-fu-grid-system-y-divides (current-environment)))
+ (define script-fu-grid-system-y-divides "'(1 g 1)"))
+
+(define (script-fu-grid-system img drw x-divides-orig y-divides-orig)
+ (define (update-segment! s x0 y0 x1 y1)
+ (aset s 0 x0)
+ (aset s 1 y0)
+ (aset s 2 x1)
+ (aset s 3 y1))
+ (define (map proc seq)
+ (if (null? seq)
+ '()
+ (cons (proc (car seq))
+ (map proc (cdr seq)))))
+ (define (convert-g l)
+ (cond ((null? l) '())
+ ((eq? (car l) 'g) (cons 1.618 (convert-g (cdr l))))
+ ((eq? (car l) '1/g) (cons 0.618 (convert-g (cdr l))))
+ ('else (cons (car l) (convert-g (cdr l))))))
+ (define (wrap-list l)
+ (define (wrap-object obj)
+ (cond ((number? obj) (string-append (number->string obj) " "))
+ ((eq? obj 'g) "g ")
+ (eq? obj '1/g) "1/g "))
+ (string-append "'(" (apply string-append (map wrap-object l)) ")"))
+ (let* ((drw-width (car (gimp-drawable-width drw)))
+ (drw-height (car (gimp-drawable-height drw)))
+ (drw-offset-x (nth 0 (gimp-drawable-offsets drw)))
+ (drw-offset-y (nth 1 (gimp-drawable-offsets drw)))
+ (grid-layer #f)
+ (segment (cons-array 4 'double))
+ (stepped-x 0)
+ (stepped-y 0)
+ (temp 0)
+ (total-step-x 0)
+ (total-step-y 0)
+ (x-divides (convert-g x-divides-orig))
+ (y-divides (convert-g y-divides-orig))
+ (total-step-x (apply + x-divides))
+ (total-step-y (apply + y-divides)))
+
+ (gimp-image-undo-group-start img)
+
+ (set! grid-layer (car (gimp-layer-copy drw TRUE)))
+ (gimp-image-insert-layer img grid-layer 0 0)
+ (gimp-drawable-edit-clear grid-layer)
+ (gimp-item-set-name grid-layer "Grid Layer")
+
+ (while (not (null? (cdr x-divides)))
+ (set! stepped-x (+ stepped-x (car x-divides)))
+ (set! temp (* drw-width (/ stepped-x total-step-x)))
+ (set! x-divides (cdr x-divides))
+ (update-segment! segment
+ (+ drw-offset-x temp) drw-offset-y
+ (+ drw-offset-x temp) (+ drw-offset-y drw-height))
+ (gimp-pencil grid-layer 4 segment))
+
+ (while (not (null? (cdr y-divides)))
+ (set! stepped-y (+ stepped-y (car y-divides)))
+ (set! temp (* drw-height (/ stepped-y total-step-y)))
+ (set! y-divides (cdr y-divides))
+ (update-segment! segment
+ drw-offset-x (+ drw-offset-y temp)
+ (+ drw-offset-x drw-width) (+ drw-offset-y temp))
+ (gimp-pencil grid-layer 4 segment))
+
+ (gimp-image-undo-group-end img)
+
+ (set! script-fu-grid-system-x-divides (wrap-list x-divides-orig))
+ (set! script-fu-grid-system-y-divides (wrap-list y-divides-orig))
+ (gimp-displays-flush)))
+
+(script-fu-register "script-fu-grid-system"
+ _"_Grid..."
+ _"Draw a grid as specified by the lists of X and Y locations using the current brush"
+ "Shuji Narazaki <narazaki@InetQ.or.jp>"
+ "Shuji Narazaki"
+ "1997"
+ "RGB*, INDEXED*, GRAY*"
+ SF-IMAGE "Image to use" 0
+ SF-DRAWABLE "Drawable to draw grid" 0
+ SF-VALUE _"X divisions" script-fu-grid-system-x-divides
+ SF-VALUE _"Y divisions" script-fu-grid-system-y-divides
+)
+
diff --git a/plug-ins/script-fu/scripts/guides-from-selection.scm b/plug-ins/script-fu/scripts/guides-from-selection.scm
new file mode 100644
index 0000000..b790c86
--- /dev/null
+++ b/plug-ins/script-fu/scripts/guides-from-selection.scm
@@ -0,0 +1,43 @@
+;; -*-scheme-*-
+
+(define (script-fu-guides-from-selection image drawable)
+ (let* (
+ (boundaries (gimp-selection-bounds image))
+ ;; non-empty INT32 TRUE if there is a selection
+ (selection (car boundaries))
+ (x1 (cadr boundaries))
+ (y1 (caddr boundaries))
+ (x2 (cadr (cddr boundaries)))
+ (y2 (caddr (cddr boundaries)))
+ )
+
+ ;; need to check for a selection or we get guides right at edges of the image
+ (if (= selection TRUE)
+ (begin
+ (gimp-image-undo-group-start image)
+
+ (gimp-image-add-vguide image x1)
+ (gimp-image-add-hguide image y1)
+ (gimp-image-add-vguide image x2)
+ (gimp-image-add-hguide image y2)
+
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+ )
+ )
+ )
+)
+
+(script-fu-register "script-fu-guides-from-selection"
+ _"New Guides from _Selection"
+ _"Create four guides around the bounding box of the current selection"
+ "Alan Horkan"
+ "Alan Horkan, 2004. Public Domain."
+ "2004-08-13"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+)
+
+(script-fu-menu-register "script-fu-guides-from-selection"
+ "<Image>/Image/Guides")
diff --git a/plug-ins/script-fu/scripts/guides-new-percent.scm b/plug-ins/script-fu/scripts/guides-new-percent.scm
new file mode 100644
index 0000000..c42d457
--- /dev/null
+++ b/plug-ins/script-fu/scripts/guides-new-percent.scm
@@ -0,0 +1,41 @@
+;; -*-scheme-*-
+
+;; Alan Horkan 2004. No copyright. Public Domain.
+
+(define (script-fu-guide-new-percent image drawable direction position)
+ (let* (
+ (width (car (gimp-image-width image)))
+ (height (car (gimp-image-height image)))
+ )
+
+ (if (= direction 0)
+ (set! position (/ (* height position) 100))
+ (set! position (/ (* width position) 100))
+ )
+
+ (if (= direction 0)
+ ;; convert position to pixel
+ (if (<= position height) (gimp-image-add-hguide image position))
+ (if (<= position width) (gimp-image-add-vguide image position))
+ )
+
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-guide-new-percent"
+ _"New Guide (by _Percent)..."
+ _"Add a guide at the position specified as a percentage of the image size"
+ "Alan Horkan"
+ "Alan Horkan, 2004"
+ "April 2004"
+ "*"
+ SF-IMAGE "Input Image" 0
+ SF-DRAWABLE "Input Drawable" 0
+ SF-OPTION _"_Direction" '(_"Horizontal"
+ _"Vertical")
+ SF-ADJUSTMENT _"_Position (in %)" '(50 0 100 1 10 2 1)
+)
+
+(script-fu-menu-register "script-fu-guide-new-percent"
+ "<Image>/Image/Guides")
diff --git a/plug-ins/script-fu/scripts/guides-new.scm b/plug-ins/script-fu/scripts/guides-new.scm
new file mode 100644
index 0000000..08217af
--- /dev/null
+++ b/plug-ins/script-fu/scripts/guides-new.scm
@@ -0,0 +1,40 @@
+;; -*-scheme-*-
+
+;; Alan Horkan 2004. Public Domain.
+;; so long as remove this block of comments from your script
+;; feel free to use it for whatever you like.
+
+(define (script-fu-guide-new image
+ drawable
+ direction
+ position)
+ (let* (
+ (width (car (gimp-image-width image)))
+ (height (car (gimp-image-height image)))
+ )
+
+ (if (= direction 0)
+ ;; check position is inside the image boundaries
+ (if (<= position height) (gimp-image-add-hguide image position))
+ (if (<= position width) (gimp-image-add-vguide image position))
+ )
+
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-guide-new"
+ _"New _Guide..."
+ _"Add a guide at the orientation and position specified (in pixels)"
+ "Alan Horkan"
+ "Alan Horkan, 2004. Public Domain."
+ "2004-04-02"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-OPTION _"_Direction" '(_"Horizontal" _"Vertical")
+ SF-ADJUSTMENT _"_Position" (list 0 0 MAX-IMAGE-SIZE 1 10 0 1)
+)
+
+(script-fu-menu-register "script-fu-guide-new"
+ "<Image>/Image/Guides")
diff --git a/plug-ins/script-fu/scripts/guides-remove-all.scm b/plug-ins/script-fu/scripts/guides-remove-all.scm
new file mode 100644
index 0000000..61cc3ed
--- /dev/null
+++ b/plug-ins/script-fu/scripts/guides-remove-all.scm
@@ -0,0 +1,30 @@
+;; -*-scheme-*-
+
+(define (script-fu-guides-remove image drawable)
+ (let* ((guide-id 0))
+ (gimp-image-undo-group-start image)
+
+ (set! guide-id (car (gimp-image-find-next-guide image 0)))
+ (while (> guide-id 0)
+ (gimp-image-delete-guide image guide-id)
+ (set! guide-id (car (gimp-image-find-next-guide image 0)))
+ )
+
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-guides-remove"
+ _"_Remove all Guides"
+ _"Remove all horizontal and vertical guides"
+ "Alan Horkan"
+ "Alan Horkan, 2004. Public Domain."
+ "April 2004"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+)
+
+(script-fu-menu-register "script-fu-guides-remove"
+ "<Image>/Image/Guides")
diff --git a/plug-ins/script-fu/scripts/images/Makefile.am b/plug-ins/script-fu/scripts/images/Makefile.am
new file mode 100644
index 0000000..5457226
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/Makefile.am
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+imagesdatadir = $(gimpdatadir)/scripts/images
+
+imagesdata_DATA = \
+ beavis.jpg \
+ texture.jpg \
+ texture1.jpg \
+ texture2.jpg \
+ texture3.jpg
+
+EXTRA_DIST = $(imagesdata_DATA)
diff --git a/plug-ins/script-fu/scripts/images/Makefile.in b/plug-ins/script-fu/scripts/images/Makefile.in
new file mode 100644
index 0000000..abc16d0
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/Makefile.in
@@ -0,0 +1,810 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plug-ins/script-fu/scripts/images
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(imagesdatadir)"
+DATA = $(imagesdata_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+imagesdatadir = $(gimpdatadir)/scripts/images
+imagesdata_DATA = \
+ beavis.jpg \
+ texture.jpg \
+ texture1.jpg \
+ texture2.jpg \
+ texture3.jpg
+
+EXTRA_DIST = $(imagesdata_DATA)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/script-fu/scripts/images/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/script-fu/scripts/images/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-imagesdataDATA: $(imagesdata_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(imagesdata_DATA)'; test -n "$(imagesdatadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(imagesdatadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(imagesdatadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(imagesdatadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(imagesdatadir)" || exit $$?; \
+ done
+
+uninstall-imagesdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(imagesdata_DATA)'; test -n "$(imagesdatadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(imagesdatadir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(imagesdatadir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-imagesdataDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-imagesdataDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-imagesdataDATA install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-imagesdataDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/script-fu/scripts/images/beavis.jpg b/plug-ins/script-fu/scripts/images/beavis.jpg
new file mode 100644
index 0000000..d555047
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/beavis.jpg
Binary files differ
diff --git a/plug-ins/script-fu/scripts/images/texture.jpg b/plug-ins/script-fu/scripts/images/texture.jpg
new file mode 100644
index 0000000..8890c7f
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/texture.jpg
Binary files differ
diff --git a/plug-ins/script-fu/scripts/images/texture1.jpg b/plug-ins/script-fu/scripts/images/texture1.jpg
new file mode 100644
index 0000000..8bb8acd
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/texture1.jpg
Binary files differ
diff --git a/plug-ins/script-fu/scripts/images/texture2.jpg b/plug-ins/script-fu/scripts/images/texture2.jpg
new file mode 100644
index 0000000..6b5d2ef
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/texture2.jpg
Binary files differ
diff --git a/plug-ins/script-fu/scripts/images/texture3.jpg b/plug-ins/script-fu/scripts/images/texture3.jpg
new file mode 100644
index 0000000..34d0988
--- /dev/null
+++ b/plug-ins/script-fu/scripts/images/texture3.jpg
Binary files differ
diff --git a/plug-ins/script-fu/scripts/lava.scm b/plug-ins/script-fu/scripts/lava.scm
new file mode 100644
index 0000000..ae62c7b
--- /dev/null
+++ b/plug-ins/script-fu/scripts/lava.scm
@@ -0,0 +1,135 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Lava effect
+; Copyright (c) 1997 Adrian Likins
+; aklikins@eos.ncsu.edu
+;
+; based on a idea by Sven Riedel <lynx@heim8.tu-clausthal.de>
+; tweaked a bit by Sven Neumann <neumanns@uni-duesseldorf.de>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-lava image
+ drawable
+ seed
+ tile_size
+ mask_size
+ gradient
+ keep-selection
+ separate-layer
+ current-grad)
+ (let* (
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (image-height (car (gimp-image-height image)))
+ (active-selection 0)
+ (selection-bounds 0)
+ (select-offset-x 0)
+ (select-offset-y 0)
+ (select-width 0)
+ (select-height 0)
+ (lava-layer 0)
+ (active-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+ (gimp-image-undo-group-start image)
+
+ (if (= (car (gimp-drawable-has-alpha drawable)) FALSE)
+ (gimp-layer-add-alpha drawable)
+ )
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ )
+
+ (set! active-selection (car (gimp-selection-save image)))
+ (gimp-image-set-active-layer image drawable)
+
+ (set! selection-bounds (gimp-selection-bounds image))
+ (set! select-offset-x (cadr selection-bounds))
+ (set! select-offset-y (caddr selection-bounds))
+ (set! select-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (set! select-height (- (caddr (cddr selection-bounds)) select-offset-y))
+
+ (if (= separate-layer TRUE)
+ (begin
+ (set! lava-layer (car (gimp-layer-new image
+ select-width
+ select-height
+ type
+ "Lava Layer"
+ 100
+ LAYER-MODE-NORMAL-LEGACY)))
+
+ (gimp-image-insert-layer image lava-layer 0 -1)
+ (gimp-layer-set-offsets lava-layer select-offset-x select-offset-y)
+ (gimp-selection-none image)
+ (gimp-drawable-edit-clear lava-layer)
+
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-image-set-active-layer image lava-layer)
+ )
+ )
+
+ (set! active-layer (car (gimp-image-get-active-layer image)))
+
+ (if (= current-grad FALSE)
+ (gimp-context-set-gradient gradient)
+ )
+
+ (plug-in-solid-noise RUN-NONINTERACTIVE image active-layer FALSE TRUE seed 2 2 2)
+ (plug-in-cubism RUN-NONINTERACTIVE image active-layer tile_size 2.5 0)
+ (plug-in-oilify RUN-NONINTERACTIVE image active-layer mask_size 0)
+ (plug-in-edge RUN-NONINTERACTIVE image active-layer 2 0 0)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE image active-layer 2 TRUE TRUE)
+ (plug-in-gradmap RUN-NONINTERACTIVE image active-layer)
+
+ (if (= keep-selection FALSE)
+ (gimp-selection-none image)
+ )
+
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-remove-channel image active-selection)
+
+ (gimp-image-undo-group-end image)
+ (gimp-context-pop)
+
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-lava"
+ _"_Lava..."
+ _"Fill the current selection with lava"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "10/12/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Seed" '(10 1 30000 1 10 0 1)
+ SF-ADJUSTMENT _"Size" '(10 0 100 1 10 0 1)
+ SF-ADJUSTMENT _"Roughness" '(7 3 50 1 10 0 0)
+ SF-GRADIENT _"Gradient" "German flag smooth"
+ SF-TOGGLE _"Keep selection" TRUE
+ SF-TOGGLE _"Separate layer" TRUE
+ SF-TOGGLE _"Use current gradient" FALSE
+)
+
+(script-fu-menu-register "script-fu-lava"
+ "<Image>/Filters/Render")
diff --git a/plug-ins/script-fu/scripts/line-nova.scm b/plug-ins/script-fu/scripts/line-nova.scm
new file mode 100644
index 0000000..8c5c35b
--- /dev/null
+++ b/plug-ins/script-fu/scripts/line-nova.scm
@@ -0,0 +1,123 @@
+;;; line-nova.scm for gimp-1.1 -*-scheme-*-
+;;; Time-stamp: <1998/11/25 13:26:44 narazaki@gimp.org>
+;;; Author Shuji Narazaki <narazaki@gimp.org>
+;;; Version 0.7
+
+(define (script-fu-line-nova img drw num-of-lines corn-deg offset variation)
+ (let* (
+ (*points* (cons-array (* 3 2) 'double))
+ (modulo fmod) ; in R4RS way
+ (pi/2 (/ *pi* 2))
+ (pi/4 (/ *pi* 4))
+ (pi3/4 (* 3 pi/4))
+ (pi5/4 (* 5 pi/4))
+ (pi3/2 (* 3 pi/2))
+ (pi7/4 (* 7 pi/4))
+ (2pi (* 2 *pi*))
+ (rad/deg (/ 2pi 360))
+ (variation/2 (/ variation 2))
+ (drw-width (car (gimp-drawable-width drw)))
+ (drw-height (car (gimp-drawable-height drw)))
+ (drw-offsets (gimp-drawable-offsets drw))
+ (old-selection FALSE)
+ (radius (max drw-height drw-width))
+ (index 0)
+ (dir-deg/line (/ 360 num-of-lines))
+ (fg-color (car (gimp-context-get-foreground)))
+ )
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+ (gimp-context-set-foreground fg-color)
+
+ (define (draw-vector beg-x beg-y direction)
+
+ (define (set-point! index x y)
+ (aset *points* (* 2 index) x)
+ (aset *points* (+ (* 2 index) 1) y)
+ )
+ (define (deg->rad rad)
+ (* (modulo rad 360) rad/deg)
+ )
+ (define (set-marginal-point beg-x beg-y direction)
+ (let (
+ (dir1 (deg->rad (+ direction corn-deg)))
+ (dir2 (deg->rad (- direction corn-deg)))
+ )
+
+ (define (aux dir index)
+ (set-point! index
+ (+ beg-x (* (cos dir) radius))
+ (+ beg-y (* (sin dir) radius)))
+ )
+
+ (aux dir1 1)
+ (aux dir2 2)
+ )
+ )
+
+ (let (
+ (dir0 (deg->rad direction))
+ (off (+ offset (- (modulo (rand) variation) variation/2)))
+ )
+
+ (set-point! 0
+ (+ beg-x (* off (cos dir0)))
+ (+ beg-y (* off (sin dir0)))
+ )
+ (set-marginal-point beg-x beg-y direction)
+ (gimp-image-select-polygon img CHANNEL-OP-ADD 6 *points*)
+ )
+ )
+
+ (gimp-image-undo-group-start img)
+
+ (set! old-selection
+ (if (eq? (car (gimp-selection-is-empty img)) TRUE)
+ #f
+ (car (gimp-selection-save img))
+ )
+ )
+
+ (gimp-selection-none img)
+ (srand (realtime))
+ (while (< index num-of-lines)
+ (draw-vector (+ (nth 0 drw-offsets) (/ drw-width 2))
+ (+ (nth 1 drw-offsets) (/ drw-height 2))
+ (* index dir-deg/line)
+ )
+ (set! index (+ index 1))
+ )
+ (gimp-drawable-edit-fill drw FILL-FOREGROUND)
+
+ (if old-selection
+ (begin
+ (gimp-image-select-item img CHANNEL-OP-REPLACE old-selection)
+ ;; (gimp-image-set-active-layer img drw)
+ ;; delete extra channel by Sven Neumann <neumanns@uni-duesseldorf.de>
+ (gimp-image-remove-channel img old-selection)
+ )
+ )
+
+ (gimp-image-undo-group-end img)
+ (gimp-displays-flush)
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-line-nova"
+ _"Line _Nova..."
+ _"Fill a layer with rays emanating outward from its center using the foreground color"
+ "Shuji Narazaki <narazaki@gimp.org>"
+ "Shuji Narazaki"
+ "1997,1998"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Number of lines" '(200 40 1000 1 1 0 1)
+ SF-ADJUSTMENT _"Sharpness (degrees)" '(1.0 0.0 10.0 0.1 1 1 1)
+ SF-ADJUSTMENT _"Offset radius" '(100 0 2000 1 1 0 1)
+ SF-ADJUSTMENT _"Randomness" '(30 1 2000 1 1 0 1)
+)
+
+(script-fu-menu-register "script-fu-line-nova"
+ "<Image>/Filters/Render")
diff --git a/plug-ins/script-fu/scripts/mkbrush.scm b/plug-ins/script-fu/scripts/mkbrush.scm
new file mode 100644
index 0000000..be204c4
--- /dev/null
+++ b/plug-ins/script-fu/scripts/mkbrush.scm
@@ -0,0 +1,272 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Make-Brush - a script for the script-fu program
+; by Seth Burgess 1997 <sjburges@ou.edu>
+;
+; 18-Dec-2000 fixed to work with the new convention (not inverted) of
+; gbr saver (jtl@gimp.org)
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-make-brush-rectangular name width height spacing)
+ (let* (
+ (img (car (gimp-image-new width height GRAY)))
+ (drawable (car (gimp-layer-new img
+ width height GRAY-IMAGE
+ "MakeBrush" 100 LAYER-MODE-NORMAL)))
+ (filename (string-append gimp-directory
+ "/brushes/r"
+ (number->string width)
+ "x"
+ (number->string height)
+ ".gbr"))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-fill drawable FILL-BACKGROUND)
+
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE 0 0 width height)
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ (file-gbr-save 1 img drawable filename filename spacing name)
+ (gimp-image-delete img)
+
+ (gimp-context-pop)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+)
+
+(script-fu-register "script-fu-make-brush-rectangular"
+ _"_Rectangular..."
+ _"Create a rectangular brush"
+ "Seth Burgess <sjburges@ou.edu>"
+ "Seth Burgess"
+ "1997"
+ ""
+ SF-STRING _"Name" "Rectangle"
+ SF-ADJUSTMENT _"Width" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Height" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Spacing" '(25 1 100 1 10 1 0)
+)
+
+(script-fu-menu-register "script-fu-make-brush-rectangular"
+ "<Brushes>")
+
+
+(define (script-fu-make-brush-rectangular-feathered name width height
+ feathering spacing)
+ (let* (
+ (widthplus (+ width feathering))
+ (heightplus (+ height feathering))
+ (img (car (gimp-image-new widthplus heightplus GRAY)))
+ (drawable (car (gimp-layer-new img
+ widthplus heightplus GRAY-IMAGE
+ "MakeBrush" 100 LAYER-MODE-NORMAL)))
+ (filename (string-append gimp-directory
+ "/brushes/r"
+ (number->string width)
+ "x"
+ (number->string height)
+ "f"
+ (number->string feathering)
+ ".gbr"))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-fill drawable FILL-BACKGROUND)
+
+ (cond
+ ((< 0 feathering)
+ (gimp-context-set-feather TRUE)
+ (gimp-context-set-feather-radius feathering feathering)
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE
+ (/ feathering 2) (/ feathering 2) width height))
+ ((>= 0 feathering)
+ (gimp-context-set-feather FALSE)
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE 0 0 width height))
+ )
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ (file-gbr-save 1 img drawable filename filename spacing name)
+ (gimp-image-delete img)
+
+ (gimp-context-pop)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+)
+
+(script-fu-register "script-fu-make-brush-rectangular-feathered"
+ _"Re_ctangular, Feathered..."
+ _"Create a rectangular brush with feathered edges"
+ "Seth Burgess <sjburges@ou.edu>"
+ "Seth Burgess"
+ "1997"
+ ""
+ SF-STRING _"Name" "Rectangle"
+ SF-ADJUSTMENT _"Width" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Height" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Feathering" '(4 1 100 1 10 0 1)
+ SF-ADJUSTMENT _"Spacing" '(25 1 100 1 10 1 0)
+)
+
+(script-fu-menu-register "script-fu-make-brush-rectangular-feathered"
+ "<Brushes>")
+
+
+(define (script-fu-make-brush-elliptical name width height spacing)
+ (let* (
+ (img (car (gimp-image-new width height GRAY)))
+ (drawable (car (gimp-layer-new img
+ width height GRAY-IMAGE
+ "MakeBrush" 100 LAYER-MODE-NORMAL)))
+ (filename (string-append gimp-directory
+ "/brushes/e"
+ (number->string width)
+ "x"
+ (number->string height)
+ ".gbr"))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-antialias TRUE)
+ (gimp-context-set-feather FALSE)
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-fill drawable FILL-BACKGROUND)
+ (gimp-context-set-background '(0 0 0))
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE 0 0 width height)
+
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ (file-gbr-save 1 img drawable filename filename spacing name)
+ (gimp-image-delete img)
+
+ (gimp-context-pop)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+)
+
+(script-fu-register "script-fu-make-brush-elliptical"
+ _"_Elliptical..."
+ _"Create an elliptical brush"
+ "Seth Burgess <sjburges@ou.edu>"
+ "Seth Burgess"
+ "1997"
+ ""
+ SF-STRING _"Name" "Ellipse"
+ SF-ADJUSTMENT _"Width" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Height" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Spacing" '(25 1 100 1 10 1 0)
+)
+
+(script-fu-menu-register "script-fu-make-brush-elliptical"
+ "<Brushes>")
+
+
+(define (script-fu-make-brush-elliptical-feathered name
+ width height
+ feathering spacing)
+ (let* (
+ (widthplus (+ feathering width)) ; add 3 for blurring
+ (heightplus (+ feathering height))
+ (img (car (gimp-image-new widthplus heightplus GRAY)))
+ (drawable (car (gimp-layer-new img
+ widthplus heightplus GRAY-IMAGE
+ "MakeBrush" 100 LAYER-MODE-NORMAL)))
+ (filename (string-append gimp-directory
+ "/brushes/e"
+ (number->string width)
+ "x"
+ (number->string height)
+ "f"
+ (number->string feathering)
+ ".gbr"))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-antialias TRUE)
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-fill drawable FILL-BACKGROUND)
+
+ (cond ((> feathering 0) ; keep from taking out gimp with stupid entry.
+ (gimp-context-set-feather TRUE)
+ (gimp-context-set-feather-radius feathering feathering)
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE
+ (/ feathering 2) (/ feathering 2)
+ width height))
+ ((<= feathering 0)
+ (gimp-context-set-feather FALSE)
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE 0 0 width height)))
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ (file-gbr-save 1 img drawable filename filename spacing name)
+ (gimp-image-delete img)
+
+ (gimp-context-pop)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+)
+
+(script-fu-register "script-fu-make-brush-elliptical-feathered"
+ _"Elli_ptical, Feathered..."
+ _"Create an elliptical brush with feathered edges"
+ "Seth Burgess <sjburges@ou.edu>"
+ "Seth Burgess"
+ "1997"
+ ""
+ SF-STRING _"Name" "Ellipse"
+ SF-ADJUSTMENT _"Width" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Height" '(20 1 200 1 10 0 1)
+ SF-ADJUSTMENT _"Feathering" '(4 1 100 1 10 0 1)
+ SF-ADJUSTMENT _"Spacing" '(25 1 100 1 10 1 0)
+)
+
+(script-fu-menu-register "script-fu-make-brush-elliptical-feathered"
+ "<Brushes>")
diff --git a/plug-ins/script-fu/scripts/old-photo.scm b/plug-ins/script-fu/scripts/old-photo.scm
new file mode 100644
index 0000000..110c313
--- /dev/null
+++ b/plug-ins/script-fu/scripts/old-photo.scm
@@ -0,0 +1,108 @@
+;
+; old-photo
+;
+;
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Branko Collin <collin@xs4all.nl> added the possibility to change
+; the border size in October 2001.
+
+; Define the function:
+
+(define (script-fu-old-photo inImage inLayer inDefocus inBorderSize inSepia inMottle inCopy)
+ (let (
+ (theImage (if (= inCopy TRUE) (car (gimp-image-duplicate inImage)) inImage))
+ (theLayer 0)
+ (theWidth 0)
+ (theHeight 0)
+ )
+ (if (= inCopy TRUE)
+ (gimp-image-undo-disable theImage)
+ (gimp-image-undo-group-start theImage)
+ )
+
+ (gimp-selection-all theImage)
+
+ (set! theLayer (car (gimp-image-flatten theImage)))
+ (if (= inDefocus TRUE)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE theImage theLayer 1.5 TRUE TRUE)
+ )
+ (if (> inBorderSize 0)
+ (script-fu-fuzzy-border theImage theLayer '(255 255 255)
+ inBorderSize TRUE 8 FALSE 100 FALSE TRUE )
+ )
+ (set! theLayer (car (gimp-image-flatten theImage)))
+
+ (if (= inSepia TRUE)
+ (begin (gimp-drawable-desaturate theLayer DESATURATE-LIGHTNESS)
+ (gimp-drawable-brightness-contrast theLayer -0.078125 -0.15625)
+ (gimp-drawable-color-balance theLayer TRANSFER-SHADOWS TRUE 30 0 -30)
+ )
+ )
+ (set! theWidth (car (gimp-image-width theImage)))
+ (set! theHeight (car (gimp-image-height theImage)))
+ (if (= inMottle TRUE)
+ (let (
+ (mLayer (car (gimp-layer-new theImage theWidth theHeight
+ RGBA-IMAGE "Mottle"
+ 100 LAYER-MODE-DARKEN-ONLY)))
+ )
+
+ (gimp-image-insert-layer theImage mLayer 0 0)
+ (gimp-selection-all theImage)
+ (gimp-drawable-edit-clear mLayer)
+ (gimp-selection-none theImage)
+ (plug-in-noisify RUN-NONINTERACTIVE theImage mLayer TRUE 0 0 0 0.5)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE theImage mLayer 5 TRUE TRUE)
+ (set! theLayer (car (gimp-image-flatten theImage)))
+ )
+ )
+ (gimp-selection-none theImage)
+
+ (if (= inCopy TRUE)
+ (begin (gimp-image-clean-all theImage)
+ (gimp-display-new theImage)
+ (gimp-image-undo-enable theImage)
+ )
+ (gimp-image-undo-group-end theImage)
+ )
+
+ (gimp-displays-flush theImage)
+ )
+)
+
+(script-fu-register "script-fu-old-photo"
+ _"_Old Photo..."
+ _"Make an image look like an old photo"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "16th April 1998"
+ "RGB* GRAY*"
+ SF-IMAGE "The image" 0
+ SF-DRAWABLE "The layer" 0
+ SF-TOGGLE _"Defocus" TRUE
+ SF-ADJUSTMENT _"Border size" '(20 0 300 1 10 0 1)
+ ; since this plug-in uses the fuzzy-border plug-in, I used the
+ ; values of the latter, with the exception of the initial value
+ ; and the 'minimum' value.
+ SF-TOGGLE _"Sepia" TRUE
+ SF-TOGGLE _"Mottle" FALSE
+ SF-TOGGLE _"Work on copy" TRUE
+)
+
+(script-fu-menu-register "script-fu-old-photo"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/palette-export.scm b/plug-ins/script-fu/scripts/palette-export.scm
new file mode 100644
index 0000000..ecb16df
--- /dev/null
+++ b/plug-ins/script-fu/scripts/palette-export.scm
@@ -0,0 +1,402 @@
+; -----------------------------------------------------------------------------
+; GIMP palette export toolkit -
+; Written by Barak Itkin <lightningismyname@gmail.com>
+;
+; This script includes various exporters for GIMP palettes, and other
+; utility function to help in exporting to other (text-based) formats.
+; See instruction on adding new exporters at the end
+;
+; -----------------------------------------------------------------------------
+; Numbers and Math
+; -----------------------------------------------------------------------------
+
+; For all the operations below, this is the order of respectable digits:
+(define conversion-digits (list "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
+ "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k"
+ "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v"
+ "w" "x" "y" "z"))
+
+; Converts a decimal number to another base. The returned number is a string
+(define (convert-decimal-to-base num base)
+ (if (< num base)
+ (list-ref conversion-digits num)
+ (let loop ((val num)
+ (order (inexact->exact (truncate (/ (log num)
+ (log base)))))
+ (result ""))
+ (let* ((power (expt base order))
+ (digit (quotient val power)))
+ (if (zero? order)
+ (string-append result (list-ref conversion-digits digit))
+ (loop (- val (* digit power))
+ (pred order)
+ (string-append result (list-ref conversion-digits digit))))))))
+
+; Convert a string representation of a number in some base, to a decimal number
+(define (convert-base-to-decimal base num-str)
+ (define (convert-char num-char)
+ (if (char-numeric? num-char)
+ (string->number (string num-char))
+ (+ 10 (- (char->integer num-char) (char->integer #\a)))
+ )
+ )
+ (define (calc base num-str num)
+ (if (equal? num-str "")
+ num
+ (calc base
+ (substring num-str 1)
+ (+ (* num base) (convert-char (string-ref num-str 0)))
+ )
+ )
+ )
+ (calc base num-str 0)
+ )
+
+; If a string num-str is shorter then size, pad it with pad-str in the
+; beginning until it's at least size long
+(define (pre-pad-number num-str size pad-str)
+ (if (< (string-length num-str) size)
+ (pre-pad-number (string-append pad-str num-str) size pad-str)
+ num-str
+ )
+ )
+
+; -----------------------------------------------------------------------------
+; Color convertors
+; -----------------------------------------------------------------------------
+
+; The standard way for representing a color would be a list of red
+; green and blue (GIMP's default)
+(define color-get-red car)
+(define color-get-green cadr)
+(define color-get-blue caddr)
+
+; Convert a color to a hexadecimal string
+; '(255 255 255) => "#ffffff"
+
+(define (color-rgb-to-hexa-decimal color)
+ (string-append "#"
+ (pre-pad-number
+ (convert-decimal-to-base (color-get-red color) 16) 2 "0")
+ (pre-pad-number
+ (convert-decimal-to-base (color-get-green color) 16) 2 "0")
+ (pre-pad-number
+ (convert-decimal-to-base (color-get-blue color) 16) 2 "0")
+ )
+ )
+
+; Convert a color to a css color
+; '(255 255 255) => "rgb(255, 255, 255)"
+(define (color-rgb-to-css color)
+ (string-append "rgb(" (number->string (color-get-red color))
+ ", " (number->string (color-get-green color))
+ ", " (number->string (color-get-blue color)) ")")
+ )
+
+; Convert a color to a simple pair of braces with comma separated values
+; '(255 255 255) => "(255, 255, 255)"
+(define (color-rgb-to-comma-seperated-list color)
+ (string-append "(" (number->string (color-get-red color))
+ ", " (number->string (color-get-green color))
+ ", " (number->string (color-get-blue color)) ")")
+ )
+
+
+; -----------------------------------------------------------------------------
+; Export utils
+; -----------------------------------------------------------------------------
+
+; List of characters that should not appear in file names
+(define illegal-file-name-chars (list #\\ #\/ #\: #\* #\? #\" #\< #\> #\|))
+
+; A function to filter a list lst by a given predicate pred
+(define (filter pred lst)
+ (if (null? lst)
+ '()
+ (if (pred (car lst))
+ (cons (car lst) (filter pred (cdr lst)))
+ (filter pred (cdr lst))
+ )
+ )
+ )
+
+; A function to check if a certain value obj is inside a list lst
+(define (contained? obj lst) (member obj lst))
+
+; This functions filters a string to have only characters which are
+; either alpha-numeric or contained in more-legal (which is a variable
+; holding a list of characters)
+(define (clean str more-legal)
+ (list->string (filter (lambda (ch) (or (char-alphabetic? ch)
+ (char-numeric? ch)
+ (contained? ch more-legal)))
+ (string->list str)))
+ )
+
+; A function that receives the a file-name, and filters out all the
+; character that shouldn't appear in file names. Then, it makes sure
+; the remaining name isn't only white-spaces. If it's only
+; white-spaces, the function returns false. Otherwise, it returns the
+; fixed file-name
+(define (valid-file-name name)
+ (let* ((clean (list->string (filter (lambda (ch)
+ (not (contained?
+ ch illegal-file-name-chars)))
+ (string->list name))))
+ (clean-without-spaces (list->string (filter (lambda (ch)
+ (not (char-whitespace?
+ ch)))
+ (string->list clean))))
+ )
+ (if (equal? clean-without-spaces "")
+ #f
+ clean
+ )
+ )
+ )
+
+; Filters a string from all the characters which are not alpha-numeric
+; (this also removes whitespaces)
+(define (name-alpha-numeric str)
+ (clean str '())
+ )
+
+; This function does the same as name-alpha-numeric, with an added
+; operation - it removes any numbers from the beginning
+(define (name-standard str)
+ (let ((cleaned (clean str '())))
+ (while (char-numeric? (string-ref cleaned 0))
+ (set! cleaned (substring cleaned 1))
+ )
+ cleaned
+ )
+ )
+
+(define name-no-conversion (lambda (obj) obj))
+(define color-none (lambda (x) ""))
+(define name-none (lambda (x) ""))
+
+(define displayln (lambda (obj) (display obj) (display "\n")))
+
+; The loop for exporting all the colors
+(define (export-palette palette-name color-convertor name-convertor
+ start name-pre name-after name-color-seperator
+ color-pre color-after entry-seperator end)
+
+ (define (write-color-line index)
+ (display name-pre)
+ (display (name-convertor
+ (car (gimp-palette-entry-get-name palette-name index))))
+ (display name-after)
+ (display name-color-seperator)
+ (display color-pre)
+ (display (color-convertor
+ (car (gimp-palette-entry-get-color palette-name index))))
+ (display color-after)
+ )
+
+ (let ((color-count (car (gimp-palette-get-colors palette-name)))
+ (i 0)
+ )
+
+ (display start)
+
+ (while (< i (- color-count 1))
+ (begin
+ (write-color-line i)
+ (display entry-seperator)
+ (set! i (+ 1 i))
+ )
+ )
+
+ (write-color-line i)
+ (display end)
+ )
+ )
+
+(define (register-palette-exporter
+ export-type export-name file-type description author copyright date)
+ (script-fu-register (string-append "gimp-palette-export-" export-type)
+ export-name
+ description
+ author
+ copyright
+ date
+ ""
+ SF-DIRNAME _"Folder for the output file" ""
+ SF-STRING _"The name of the file to create (if a file with this name already exist, it will be replaced)"
+ (string-append "palette." file-type)
+ )
+ (script-fu-menu-register (string-append "gimp-palette-export-" export-type)
+ "<Palettes>/Export as")
+ )
+
+(define (bad-file-name)
+ (gimp-message (string-append _"The filename you entered is not a suitable name for a file."
+ "\n\n"
+ _"All characters in the name are either white-spaces or characters which can not appear in filenames.")))
+
+; -----------------------------------------------------------------------------
+; Exporters
+; -----------------------------------------------------------------------------
+
+(define (gimp-palette-export-css directory-name file-name)
+ (let ((valid-name (valid-file-name file-name)))
+ (if valid-name
+ (with-output-to-file (string-append
+ directory-name DIR-SEPARATOR file-name)
+ (lambda () (export-palette (car (gimp-context-get-palette))
+ color-rgb-to-css
+ name-alpha-numeric ; name-convertor
+ "/* Generated with GIMP Palette Export */\n" ; start
+ "." ; name-pre
+ "" ; name-after
+ " { " ; name-color-seperator
+ "color: " ; color-pre
+ " }" ; color-after
+ "\n" ; entry-seperator
+ "" ; end
+ )))
+ (bad-file-name)
+ )
+ )
+ )
+(register-palette-exporter "css" "_CSS stylesheet..." "css"
+ (string-append _"Export the active palette as a CSS stylesheet with the color entry name as their class name, and the color itself as the color attribute")
+ "Barak Itkin <lightningismyname@gmail.com>"
+ "Barak Itkin" "May 15th, 2009")
+
+(define (gimp-palette-export-php directory-name file-name)
+ (let ((valid-name (valid-file-name file-name)))
+ (if valid-name
+ (with-output-to-file (string-append
+ directory-name DIR-SEPARATOR file-name)
+ (lambda () (export-palette (car (gimp-context-get-palette))
+ color-rgb-to-hexa-decimal
+ name-standard ; name-convertor
+ "<?php\n/* Generated with GIMP Palette Export */\n$colors={\n" ; start
+ "'" ; name-pre
+ "'" ; name-after
+ " => " ; name-color-seperator
+ "'" ; color-pre
+ "'" ; color-after
+ ",\n" ; entry-seperator
+ "}\n?>" ; end
+ )))
+ (bad-file-name)
+ )
+ )
+ )
+(register-palette-exporter "php" "P_HP dictionary..." "php"
+ _"Export the active palette as a PHP dictionary (name => color)"
+ "Barak Itkin <lightningismyname@gmail.com>"
+ "Barak Itkin" "May 15th, 2009")
+
+(define (gimp-palette-export-python directory-name file-name)
+ (let ((valid-name (valid-file-name file-name)))
+ (if valid-name
+ (with-output-to-file (string-append
+ directory-name DIR-SEPARATOR file-name)
+ (lambda ()
+ (let ((palette-name (car (gimp-context-get-palette))))
+ (begin (displayln "# Generated with GIMP Palette Export")
+ (displayln (string-append
+ "# Based on the palette " palette-name))
+ (export-palette palette-name
+ color-rgb-to-hexa-decimal
+ name-standard ; name-convertor
+ "colors={\n" ; start
+ "'" ; name-pre
+ "'" ; name-after
+ ": " ; name-color-seperator
+ "'" ; color-pre
+ "'" ; color-after
+ ",\n" ; entry-seperator
+ "}" ; end
+ ))))
+ )
+ (bad-file-name)
+ )
+ )
+ )
+(register-palette-exporter "python" "_Python dictionary" "py"
+ _"Export the active palette as a Python dictionary (name: color)"
+ "Barak Itkin <lightningismyname@gmail.com>"
+ "Barak Itkin" "May 15th, 2009")
+
+(define (gimp-palette-export-text directory-name file-name)
+ (let ((valid-name (valid-file-name file-name)))
+ (if valid-name
+ (with-output-to-file (string-append
+ directory-name DIR-SEPARATOR file-name)
+ (lambda ()
+ (export-palette (car (gimp-context-get-palette))
+ color-rgb-to-hexa-decimal
+ name-none ; name-convertor
+ "" ; start
+ "" ; name-pre
+ "" ; name-after
+ "" ; name-color-seperator
+ "" ; color-pre
+ "" ; color-after
+ "\n" ; entry-seperator
+ "" ; end
+ )
+ )
+ )
+ (bad-file-name)
+ )
+ )
+ )
+(register-palette-exporter "text" "_Text file..." "txt"
+ _"Write all the colors in a palette to a text file, one hexadecimal value per line (no names)"
+ "Barak Itkin <lightningismyname@gmail.com>"
+ "Barak Itkin" "May 15th, 2009")
+
+(define (gimp-palette-export-java directory-name file-name)
+ (let ((valid-name (valid-file-name file-name)))
+ (if valid-name
+ (with-output-to-file (string-append directory-name
+ DIR-SEPARATOR file-name)
+ (lambda ()
+ (let ((palette-name (car (gimp-context-get-palette))))
+ (begin (displayln "")
+ (displayln "import java.awt.Color;")
+ (displayln "import java.util.Hashtable;")
+ (displayln "")
+ (displayln "// Generated with GIMP palette Export ")
+ (displayln (string-append
+ "// Based on the palette " palette-name))
+ (displayln (string-append
+ "public class "
+ (name-standard palette-name) " {"))
+ (displayln "")
+ (displayln " Hashtable<String, Color> colors;")
+ (displayln "")
+ (displayln (string-append
+ " public "
+ (name-standard palette-name) "() {"))
+ (export-palette (car (gimp-context-get-palette))
+ color-rgb-to-comma-seperated-list
+ name-no-conversion
+ " colors = new Hashtable<String,Color>();\n" ; start
+ " colors.put(\"" ; name-pre
+ "\"" ; name-after
+ ", " ; name-color-seperator
+ "new Color" ; color-pre
+ ");" ; color-after
+ "\n" ; entry-seperator
+ "\n }" ; end
+ )
+ (display "\n}"))))
+ )
+ (bad-file-name)
+ )
+ )
+ )
+
+(register-palette-exporter "java" "J_ava map..." "java"
+ _"Export the active palette as a java.util.Hashtable<String, Color>"
+ "Barak Itkin <lightningismyname@gmail.com>"
+ "Barak Itkin" "May 15th, 2009")
+
diff --git a/plug-ins/script-fu/scripts/paste-as-brush.scm b/plug-ins/script-fu/scripts/paste-as-brush.scm
new file mode 100644
index 0000000..062e97d
--- /dev/null
+++ b/plug-ins/script-fu/scripts/paste-as-brush.scm
@@ -0,0 +1,74 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; script-fu-paste-as-brush
+; Based on select-to-brush by Copyright (c) 1997 Adrian Likins
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-paste-as-brush name filename spacing)
+
+ (let* ((brush-image (car (gimp-edit-paste-as-new-image)))
+ (brush-draw 0)
+ (type 0)
+ (path 0))
+
+ (if (= TRUE (car (gimp-image-is-valid brush-image)))
+ (begin
+ (set! brush-draw (car (gimp-image-get-active-drawable brush-image)))
+ (set! type (car (gimp-drawable-type brush-draw)))
+ (set! path (string-append gimp-directory
+ "/brushes/"
+ filename
+ (number->string brush-image)
+ ".gbr"))
+
+ (if (= type GRAYA-IMAGE)
+ (begin
+ (gimp-context-push)
+ (gimp-context-set-background '(255 255 255))
+ (set! brush-draw (car (gimp-image-flatten brush-image)))
+ (gimp-context-pop)
+ )
+ )
+
+ (file-gbr-save RUN-NONINTERACTIVE
+ brush-image brush-draw path path
+ spacing name)
+
+ (gimp-image-delete brush-image)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+ (gimp-message _"There is no image data in the clipboard to paste.")
+ )
+ )
+)
+
+(script-fu-register "script-fu-paste-as-brush"
+ _"New _Brush..."
+ _"Paste the clipboard contents into a new brush"
+ "Michael Natterer <mitch@gimp.org>"
+ "Michael Natterer"
+ "2005-09-25"
+ ""
+ SF-STRING _"_Brush name" "My Brush"
+ SF-STRING _"_File name" "mybrush"
+ SF-ADJUSTMENT _"_Spacing" '(25 0 1000 1 1 1 0)
+)
+
+(script-fu-menu-register "script-fu-paste-as-brush"
+ "<Image>/Edit/Paste as")
diff --git a/plug-ins/script-fu/scripts/paste-as-pattern.scm b/plug-ins/script-fu/scripts/paste-as-pattern.scm
new file mode 100644
index 0000000..01381a2
--- /dev/null
+++ b/plug-ins/script-fu/scripts/paste-as-pattern.scm
@@ -0,0 +1,61 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; script-fu-paste-as-pattern
+; Based on select-to-pattern by Cameron Gregory, http://www.flamingtext.com/
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-paste-as-pattern name filename)
+ (let* ((pattern-image (car (gimp-edit-paste-as-new-image)))
+ (pattern-draw 0)
+ (path 0))
+
+ (if (= TRUE (car (gimp-image-is-valid pattern-image)))
+ (begin
+ (set! pattern-draw (car (gimp-image-get-active-drawable pattern-image)))
+ (set! path (string-append gimp-directory
+ "/patterns/"
+ filename
+ (number->string pattern-image)
+ ".pat"))
+
+ (file-pat-save RUN-NONINTERACTIVE
+ pattern-image pattern-draw path path
+ name)
+
+ (gimp-image-delete pattern-image)
+
+ (gimp-patterns-refresh)
+ (gimp-context-set-pattern name)
+ )
+ (gimp-message _"There is no image data in the clipboard to paste.")
+ )
+ )
+)
+
+(script-fu-register "script-fu-paste-as-pattern"
+ _"New _Pattern..."
+ _"Paste the clipboard contents into a new pattern"
+ "Michael Natterer <mitch@gimp.org>"
+ "Michael Natterer"
+ "2005-09-25"
+ ""
+ SF-STRING _"_Pattern name" "My Pattern"
+ SF-STRING _"_File name" "mypattern"
+)
+
+(script-fu-menu-register "script-fu-paste-as-pattern"
+ "<Image>/Edit/Paste as")
diff --git a/plug-ins/script-fu/scripts/perspective-shadow.scm b/plug-ins/script-fu/scripts/perspective-shadow.scm
new file mode 100644
index 0000000..1eb40e3
--- /dev/null
+++ b/plug-ins/script-fu/scripts/perspective-shadow.scm
@@ -0,0 +1,217 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; perspective-shadow.scm version 1.2 2000/11/08
+;
+; Copyright (C) 1997-2000 Sven Neumann <sven@gimp.org>
+;
+;
+; Adds a perspective shadow of the current selection or alpha-channel
+; as a layer below the active layer
+;
+
+(define (script-fu-perspective-shadow image
+ drawable
+ alpha
+ rel-distance
+ rel-length
+ shadow-blur
+ shadow-color
+ shadow-opacity
+ interpolation
+ allow-resize)
+ (let* (
+ (shadow-blur (max shadow-blur 0))
+ (shadow-opacity (min shadow-opacity 100))
+ (shadow-opacity (max shadow-opacity 0))
+ (rel-length (abs rel-length))
+ (alpha (* (/ alpha 180) *pi*))
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (image-height (car (gimp-image-height image)))
+ (from-selection 0)
+ (active-selection 0)
+ (shadow-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (if (> rel-distance 24) (set! rel-distance 999999))
+ (if (= rel-distance rel-length) (set! rel-distance (+ rel-distance 0.01)))
+
+ (gimp-image-undo-group-start image)
+
+ (gimp-layer-add-alpha drawable)
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! from-selection FALSE))
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))))
+
+ (let* ((selection-bounds (gimp-selection-bounds image))
+ (select-offset-x (cadr selection-bounds))
+ (select-offset-y (caddr selection-bounds))
+ (select-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (select-height (- (caddr (cddr selection-bounds)) select-offset-y))
+
+ (abs-length (* rel-length select-height))
+ (abs-distance (* rel-distance select-height))
+ (half-bottom-width (/ select-width 2))
+ (half-top-width (* half-bottom-width
+ (/ (- rel-distance rel-length) rel-distance)))
+
+ (x0 (+ select-offset-x (+ (- half-bottom-width half-top-width)
+ (* (cos alpha) abs-length))))
+ (y0 (+ select-offset-y (- select-height
+ (* (sin alpha) abs-length))))
+ (x1 (+ x0 (* 2 half-top-width)))
+ (y1 y0)
+ (x2 select-offset-x)
+ (y2 (+ select-offset-y select-height))
+ (x3 (+ x2 select-width))
+ (y3 y2)
+
+ (shadow-width (+ (- (max x1 x3) (min x0 x2)) (* 2 shadow-blur)))
+ (shadow-height (+ (- (max y1 y3) (min y0 y2)) (* 2 shadow-blur)))
+ (shadow-offset-x (- (min x0 x2) shadow-blur))
+ (shadow-offset-y (- (min y0 y2) shadow-blur)))
+
+
+ (set! shadow-layer (car (gimp-layer-new image
+ select-width
+ select-height
+ type
+ "Perspective Shadow"
+ shadow-opacity
+ LAYER-MODE-NORMAL)))
+
+
+ (gimp-image-insert-layer image shadow-layer 0 -1)
+ (gimp-layer-set-offsets shadow-layer select-offset-x select-offset-y)
+ (gimp-drawable-fill shadow-layer FILL-TRANSPARENT)
+ (gimp-context-set-background shadow-color)
+ (gimp-drawable-edit-fill shadow-layer FILL-BACKGROUND)
+ (gimp-selection-none image)
+
+ (if (= allow-resize TRUE)
+ (let* ((new-image-width image-width)
+ (new-image-height image-height)
+ (image-offset-x 0)
+ (image-offset-y 0))
+
+ (if (< shadow-offset-x 0)
+ (begin
+ (set! image-offset-x (abs shadow-offset-x))
+ (set! new-image-width (+ new-image-width image-offset-x))
+ ; adjust to new coordinate system
+ (set! x0 (+ x0 image-offset-x))
+ (set! x1 (+ x1 image-offset-x))
+ (set! x2 (+ x2 image-offset-x))
+ (set! x3 (+ x3 image-offset-x))
+ ))
+
+ (if (< shadow-offset-y 0)
+ (begin
+ (set! image-offset-y (abs shadow-offset-y))
+ (set! new-image-height (+ new-image-height image-offset-y))
+ ; adjust to new coordinate system
+ (set! y0 (+ y0 image-offset-y))
+ (set! y1 (+ y1 image-offset-y))
+ (set! y2 (+ y2 image-offset-y))
+ (set! y3 (+ y3 image-offset-y))
+ ))
+
+ (if (> (+ shadow-width shadow-offset-x) new-image-width)
+ (set! new-image-width (+ shadow-width shadow-offset-x)))
+
+ (if (> (+ shadow-height shadow-offset-y) new-image-height)
+ (set! new-image-height (+ shadow-height shadow-offset-y)))
+ (gimp-image-resize image
+ new-image-width
+ new-image-height
+ image-offset-x
+ image-offset-y)))
+
+ (gimp-context-set-transform-direction TRANSFORM-FORWARD)
+ (gimp-context-set-interpolation interpolation)
+ (gimp-context-set-transform-recursion 3)
+ (gimp-context-set-transform-resize TRANSFORM-RESIZE-ADJUST)
+
+ (gimp-item-transform-perspective shadow-layer
+ x0 y0
+ x1 y1
+ x2 y2
+ x3 y3)
+
+ (if (>= shadow-blur 1.0)
+ (begin
+ (gimp-layer-set-lock-alpha shadow-layer FALSE)
+ (gimp-layer-resize shadow-layer
+ shadow-width
+ shadow-height
+ shadow-blur
+ shadow-blur)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ image
+ shadow-layer
+ shadow-blur
+ TRUE
+ TRUE))))
+
+ (if (= from-selection TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-drawable-edit-clear shadow-layer)
+ (gimp-image-remove-channel image active-selection)))
+
+ (if (and
+ (= (car (gimp-layer-is-floating-sel drawable)) 0)
+ (= from-selection FALSE))
+ (gimp-image-raise-item image drawable))
+
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-perspective-shadow"
+ _"_Perspective..."
+ _"Add a perspective shadow to the selected region (or alpha)"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "2000/11/08"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Angle" '(45 0 180 1 10 1 0)
+ SF-ADJUSTMENT _"Relative distance of horizon" '(5 0.1 24.1 0.1 1 1 1)
+ SF-ADJUSTMENT _"Relative length of shadow" '(1 0.1 24 0.1 1 1 1)
+ SF-ADJUSTMENT _"Blur radius" '(3 0 1024 1 10 0 0)
+ SF-COLOR _"Color" '(0 0 0)
+ SF-ADJUSTMENT _"Opacity" '(80 0 100 1 10 0 0)
+ SF-ENUM _"Interpolation" '("InterpolationType" "linear")
+ SF-TOGGLE _"Allow resizing" FALSE
+)
+
+(script-fu-menu-register "script-fu-perspective-shadow"
+ "<Image>/Filters/Light and Shadow/Shadow")
diff --git a/plug-ins/script-fu/scripts/plug-in-compat.init b/plug-ins/script-fu/scripts/plug-in-compat.init
new file mode 100644
index 0000000..dd68c2c
--- /dev/null
+++ b/plug-ins/script-fu/scripts/plug-in-compat.init
@@ -0,0 +1,24 @@
+; The Scheme code in this file provides some compatibility with
+; scripts that were originally written for use with older versions of
+; GIMP.
+;
+; It provides PDB procedures that used to be provided by plug-ins that
+; were since then removed from the GIMP distribution. You should not
+; use these in newly written scripts as the functions defined here may
+; be removed at some later date.
+
+
+(define (plug-in-color-map run-mode img layer
+ src-color-1 src-color-2 dest-color-1 dest-color-2
+ map-mode)
+ (gimp-levels layer HISTOGRAM-RED
+ (car src-color-1) (car src-color-2) 1.0
+ (- 255 (car dest-color-1)) (- 255 (car dest-color-2)))
+ (gimp-levels layer HISTOGRAM-GREEN
+ (cadr src-color-1) (cadr src-color-2) 1.0
+ (- 255 (cadr dest-color-1)) (- 255 (cadr dest-color-2)))
+ (gimp-levels layer HISTOGRAM-BLUE
+ (caddr src-color-1) (caddr src-color-2) 1.0
+ (- 255 (caddr dest-color-1)) (- 255 (caddr dest-color-2)))
+ (gimp-levels layer HISTOGRAM-VALUE 0 255 1.0 255 0)
+)
diff --git a/plug-ins/script-fu/scripts/predator.scm b/plug-ins/script-fu/scripts/predator.scm
new file mode 100644
index 0000000..cd1ab14
--- /dev/null
+++ b/plug-ins/script-fu/scripts/predator.scm
@@ -0,0 +1,137 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Predator effect
+; Copyright (c) 1997 Adrian Likins
+; aklikins@eos.ncsu.ed
+;
+; The idea here is too make the image/selection look sort of like
+; the view the predator had in the movies. ie, kind of a thermogram
+; type of thing. Works best on colorful rgb images.
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-predator image
+ drawable
+ edge-amount
+ pixelize
+ pixel-size
+ keep-selection
+ separate-layer)
+ (let* (
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (image-height (car (gimp-image-height image)))
+ (active-selection 0)
+ (from-selection 0)
+ (selection-bounds 0)
+ (select-offset-x 0)
+ (select-offset-y 0)
+ (select-width 0)
+ (select-height 0)
+ (effect-layer 0)
+ (active-layer 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+ (gimp-image-undo-group-start image)
+ (gimp-layer-add-alpha drawable)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! active-selection (car (gimp-selection-save image)))
+ (set! from-selection FALSE)
+ )
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))
+ )
+ )
+
+ (set! selection-bounds (gimp-selection-bounds image))
+ (set! select-offset-x (cadr selection-bounds))
+ (set! select-offset-y (caddr selection-bounds))
+ (set! select-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (set! select-height (- (caddr (cddr selection-bounds)) select-offset-y))
+
+ (if (= separate-layer TRUE)
+ (begin
+ (set! effect-layer (car (gimp-layer-new image
+ select-width
+ select-height
+ type
+ "glow layer"
+ 100
+ LAYER-MODE-NORMAL))
+ )
+
+ (gimp-layer-set-offsets effect-layer select-offset-x select-offset-y)
+ (gimp-image-insert-layer image effect-layer 0 -1)
+ (gimp-selection-none image)
+ (gimp-drawable-edit-clear effect-layer)
+
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-edit-copy drawable)
+ (let ((floating-sel (car (gimp-edit-paste effect-layer FALSE))))
+ (gimp-floating-sel-anchor floating-sel)
+ )
+ (gimp-image-set-active-layer image effect-layer)
+ )
+ (set! effect-layer drawable)
+ )
+ (set! active-layer effect-layer)
+
+ ; all the fun stuff goes here
+ (if (= pixelize TRUE)
+ (plug-in-pixelize RUN-NONINTERACTIVE image active-layer pixel-size)
+ )
+ (plug-in-max-rgb RUN-NONINTERACTIVE image active-layer 0)
+ (plug-in-edge RUN-NONINTERACTIVE image active-layer edge-amount 1 0)
+
+ ; clean up the selection copy
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+
+ (if (= keep-selection FALSE)
+ (gimp-selection-none image)
+ )
+
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-remove-channel image active-selection)
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-predator"
+ _"_Predator..."
+ _"Add a 'Predator' effect to the selected region (or alpha)"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "10/12/97"
+ "RGB*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Edge amount" '(2 0 24 1 1 0 0)
+ SF-TOGGLE _"Pixelize" TRUE
+ SF-ADJUSTMENT _"Pixel amount" '(3 1 16 1 1 0 0)
+ SF-TOGGLE _"Keep selection" TRUE
+ SF-TOGGLE _"Separate layer" TRUE
+)
+
+(script-fu-menu-register "script-fu-predator"
+ "<Image>/Filters/Artistic")
diff --git a/plug-ins/script-fu/scripts/reverse-layers.scm b/plug-ins/script-fu/scripts/reverse-layers.scm
new file mode 100644
index 0000000..d7e2882
--- /dev/null
+++ b/plug-ins/script-fu/scripts/reverse-layers.scm
@@ -0,0 +1,53 @@
+; reverse-layers.scm: Reverse the order of layers in the current image.
+; Copyright (C) 2006 by Akkana Peck.
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define (script-fu-reverse-layers img drawable)
+ (let* (
+ (layers (gimp-image-get-layers img))
+ (num-layers (car layers))
+ (layer-array (cadr layers))
+ (i (- num-layers 1))
+ )
+
+ (gimp-image-undo-group-start img)
+
+ (while (>= i 0)
+ (let ((layer (aref layer-array i)))
+ (if (= (car (gimp-layer-is-floating-sel layer)) FALSE)
+ (gimp-image-lower-item-to-bottom img layer))
+ )
+
+ (set! i (- i 1))
+ )
+
+ (gimp-image-undo-group-end img)
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-reverse-layers"
+ _"Reverse Layer _Order"
+ _"Reverse the order of layers in the image"
+ "Akkana Peck"
+ "Akkana Peck"
+ "August 2006"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+)
+
+(script-fu-menu-register "script-fu-reverse-layers"
+ "<Image>/Layer/Stack")
diff --git a/plug-ins/script-fu/scripts/ripply-anim.scm b/plug-ins/script-fu/scripts/ripply-anim.scm
new file mode 100644
index 0000000..25a2462
--- /dev/null
+++ b/plug-ins/script-fu/scripts/ripply-anim.scm
@@ -0,0 +1,83 @@
+; "Rippling Image" animation generator (ripply-anim.scm)
+; Adam D. Moss (adam@foxbox.org)
+; 97/05/18
+; Revised by Saul Goode April 2015.
+;
+; Designed to be used in conjunction with a plugin capable
+; of saving animations (i.e. the GIF plugin).
+;
+
+(define (script-fu-ripply-anim image drawable displacement num-frames edge-type)
+ (let* ((width (car (gimp-drawable-width drawable)))
+ (height (car (gimp-drawable-height drawable)))
+ (work-image (car (gimp-image-new width
+ height
+ (quotient (car (gimp-drawable-type drawable))
+ 2))))
+ (map-layer (car (gimp-layer-new work-image
+ width
+ height
+ (car (gimp-drawable-type drawable))
+ "Ripple Map"
+ 100
+ LAYER-MODE-NORMAL))))
+ (gimp-context-push)
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+ (gimp-image-undo-disable work-image)
+
+ ; Create a tile-able displacement map in the first layer
+ (gimp-context-set-background '(127 127 127))
+ (gimp-image-insert-layer work-image map-layer 0 0)
+ (gimp-drawable-edit-fill map-layer FILL-BACKGROUND)
+ (plug-in-noisify RUN-NONINTERACTIVE work-image map-layer FALSE 1.0 1.0 1.0 0.0)
+ (plug-in-tile RUN-NONINTERACTIVE work-image map-layer (* width 3) (* height 3) FALSE)
+ (plug-in-gauss-iir RUN-NONINTERACTIVE work-image map-layer 35 TRUE TRUE)
+ (gimp-drawable-equalize map-layer TRUE)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE work-image map-layer 5 TRUE TRUE)
+ (gimp-drawable-equalize map-layer TRUE)
+ (gimp-image-crop work-image width height width height)
+
+ ; Create the frame layers
+ (let loop ((remaining-frames num-frames))
+ (unless (zero? remaining-frames)
+ (let ((frame-layer (car (gimp-layer-new-from-drawable drawable work-image))))
+ (gimp-image-insert-layer work-image frame-layer 0 0)
+ (gimp-item-set-name frame-layer
+ (string-append "Frame "
+ (number->string (+ 1 (- num-frames
+ remaining-frames)))
+ " (replace)"))
+ (plug-in-displace RUN-NONINTERACTIVE work-image frame-layer
+ displacement displacement
+ TRUE TRUE map-layer map-layer (+ edge-type 1))
+ (gimp-item-set-visible frame-layer TRUE))
+ (gimp-drawable-offset map-layer
+ TRUE
+ OFFSET-BACKGROUND
+ (/ width num-frames)
+ (/ height num-frames))
+ (loop (- remaining-frames 1))))
+
+ (gimp-image-remove-layer work-image map-layer)
+ (gimp-image-undo-enable work-image)
+ (gimp-display-new work-image)
+
+ (gimp-context-pop)))
+
+(script-fu-register "script-fu-ripply-anim"
+ _"_Rippling..."
+ _"Create a multi-layer image by adding a ripple effect to the current layer"
+ "Adam D. Moss (adam@foxbox.org), Saul Goode"
+ "Adam D. Moss, Saul Goode"
+ "1997, 2015"
+ "RGB* GRAY*"
+ SF-IMAGE "Image to animage" 0
+ SF-DRAWABLE "Drawable to animate" 0
+ SF-ADJUSTMENT _"Rippling strength" '(3 0 256 1 10 1 0)
+ SF-ADJUSTMENT _"Number of frames" '(15 0 256 1 10 0 1)
+ SF-OPTION _"Edge behavior" '(_"Wrap" _"Smear" _"Black")
+ )
+
+(script-fu-menu-register "script-fu-ripply-anim"
+ "<Image>/Filters/Animation/Animators")
diff --git a/plug-ins/script-fu/scripts/round-corners.scm b/plug-ins/script-fu/scripts/round-corners.scm
new file mode 100644
index 0000000..53711d5
--- /dev/null
+++ b/plug-ins/script-fu/scripts/round-corners.scm
@@ -0,0 +1,149 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; round-corners.scm version 1.02 1999/12/21
+;
+; CHANGE-LOG:
+; 1.00 - initial release
+; 1.01 - some code cleanup, no real changes
+;
+; Copyright (C) 1997-1999 Sven Neumann <sven@gimp.org>
+;
+;
+; Rounds the corners of an image, optionally adding a drop-shadow and
+; a background layer
+;
+; The script works on RGB and grayscale images that contain only
+; one layer. It creates a copy of the image or can optionally work
+; on the original. The script uses the current background color to
+; create a background layer. It makes a call to the script drop-shadow.
+;
+; This script is derived from my script add-shadow, which has become
+; obsolete now.
+
+
+
+(define (script-fu-round-corners img
+ drawable
+ radius
+ shadow-toggle
+ shadow-x
+ shadow-y
+ shadow-blur
+ background-toggle
+ work-on-copy)
+ (let* ((shadow-blur (abs shadow-blur))
+ (radius (abs radius))
+ (diam (* 2 radius))
+ (width (car (gimp-image-width img)))
+ (height (car (gimp-image-height img)))
+ (image (cond ((= work-on-copy TRUE)
+ (car (gimp-image-duplicate img)))
+ ((= work-on-copy FALSE)
+ img)))
+ ; active drawable is not necessarily the active layer
+ (pic-layer (car (gimp-image-get-active-layer image)))
+ (type (car (gimp-drawable-type-with-alpha pic-layer)))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (if (= work-on-copy TRUE)
+ (gimp-image-undo-disable image)
+ (gimp-image-undo-group-start image)
+ )
+
+ ; add an alpha channel to the image
+ (gimp-layer-add-alpha pic-layer)
+
+ ; round the edges
+ (gimp-selection-none image)
+ (gimp-image-select-rectangle image CHANNEL-OP-ADD 0 0 radius radius)
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT 0 0 diam diam)
+ (gimp-image-select-rectangle image CHANNEL-OP-ADD (- width radius) 0 radius radius)
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT (- width diam) 0 diam diam)
+ (gimp-image-select-rectangle image CHANNEL-OP-ADD 0 (- height radius) radius radius)
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT 0 (- height diam) diam diam)
+ (gimp-image-select-rectangle image CHANNEL-OP-ADD (- width radius) (- height radius)
+ radius radius)
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT (- width diam) (- height diam)
+ diam diam)
+ (gimp-drawable-edit-clear pic-layer)
+ (gimp-selection-none image)
+
+ ; optionally add a shadow
+ (if (= shadow-toggle TRUE)
+ (begin
+ (script-fu-drop-shadow image
+ pic-layer
+ shadow-x
+ shadow-y
+ shadow-blur
+ '(0 0 0)
+ 80
+ TRUE)
+ (set! width (car (gimp-image-width image)))
+ (set! height (car (gimp-image-height image)))))
+
+ ; optionally add a background
+ (if (= background-toggle TRUE)
+ (let* ((bg-layer (car (gimp-layer-new image
+ width
+ height
+ type
+ "Background"
+ 100
+ LAYER-MODE-NORMAL))))
+ (gimp-drawable-fill bg-layer FILL-BACKGROUND)
+ (gimp-image-insert-layer image bg-layer 0 -1)
+ (gimp-image-raise-item image pic-layer)
+ (if (= shadow-toggle TRUE)
+ (gimp-image-lower-item image bg-layer))))
+
+; clean up after the script
+ (if (= work-on-copy TRUE)
+ (gimp-image-undo-enable image)
+ (gimp-image-undo-group-end image)
+ )
+
+ (if (= work-on-copy TRUE)
+ (gimp-display-new image))
+ (gimp-context-pop)
+ (gimp-displays-flush))
+)
+
+(script-fu-register "script-fu-round-corners"
+ _"_Round Corners..."
+ _"Round the corners of an image and optionally add a drop-shadow and background"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "1999/12/21"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Edge radius" '(15 0 4096 1 10 0 1)
+ SF-TOGGLE _"Add drop-shadow" TRUE
+ SF-ADJUSTMENT _"Shadow X offset" '(8 -4096 4096 1 10 0 1)
+ SF-ADJUSTMENT _"Shadow Y offset" '(8 -4096 4096 1 10 0 1)
+ SF-ADJUSTMENT _"Blur radius" '(15 0 1024 1 10 0 1)
+ SF-TOGGLE _"Add background" TRUE
+ SF-TOGGLE _"Work on copy" TRUE
+)
+
+(script-fu-menu-register "script-fu-round-corners"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/script-fu-compat.init b/plug-ins/script-fu/scripts/script-fu-compat.init
new file mode 100644
index 0000000..865cf80
--- /dev/null
+++ b/plug-ins/script-fu/scripts/script-fu-compat.init
@@ -0,0 +1,457 @@
+;The Scheme code in this file provides some compatibility with scripts that
+;were originally written for use with the older SIOD based Script-Fu plug-in
+;of GIMP.
+;
+;All items defined in this file except for the random number routines are
+;deprecated. Existing scripts should be updated to avoid the use of the
+;compatibility functions and define statements which follow the random number
+;generator routines.
+;
+;The items marked as deprecated at the end of this file may be removed
+;at some later date.
+
+
+;The random number generator routines below have been slightly reformatted.
+;A couple of define blocks which are not needed have been commented out.
+;It has also been extended to enable it to generate numbers with exactly 31
+;bits or more.
+;The original file was called rand2.scm and can be found in:
+;http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/code/math/random/
+
+; Minimal Standard Random Number Generator
+; Park & Miller, CACM 31(10), Oct 1988, 32 bit integer version.
+; better constants, as proposed by Park.
+; By Ozan Yigit
+
+;(define *seed* 1)
+
+(define (srand seed)
+ (set! *seed* seed)
+ *seed*
+)
+
+(define (msrg-rand)
+ (let (
+ (A 48271)
+ (M 2147483647)
+ (Q 44488)
+ (R 3399)
+ )
+ (let* (
+ (hi (quotient *seed* Q))
+ (lo (modulo *seed* Q))
+ (test (- (* A lo) (* R hi)))
+ )
+ (if (> test 0)
+ (set! *seed* test)
+ (set! *seed* (+ test M))
+ )
+ )
+ )
+ *seed*
+)
+
+; poker test
+; seed 1
+; cards 0-9 inclusive (random 10)
+; five cards per hand
+; 10000 hands
+;
+; Poker Hand Example Probability Calculated
+; 5 of a kind (aaaaa) 0.0001 0
+; 4 of a kind (aaaab) 0.0045 0.0053
+; Full house (aaabb) 0.009 0.0093
+; 3 of a kind (aaabc) 0.072 0.0682
+; two pairs (aabbc) 0.108 0.1104
+; Pair (aabcd) 0.504 0.501
+; Bust (abcde) 0.3024 0.3058
+
+(define (random n)
+ (define (internal-random n)
+ (let* (
+ (n (inexact->exact (truncate n)))
+ (M 2147483647)
+ (slop (modulo M (abs n)))
+ )
+ (let loop ((r (msrg-rand)))
+ (if (>= r slop)
+ (modulo r n)
+ (loop (msrg-rand))
+ )
+ )
+ )
+ )
+
+ ; Negative numbers have a bigger range in twos complement platforms
+ ; (nearly all platforms out there) than positive ones, so we deal with
+ ; the numbers in negative form.
+ (if (> n 0)
+ (+ n (random (- n)))
+
+ (if (>= n -2147483647)
+ (internal-random n)
+
+ ; 31-or-more-bits number requested - needs multiple extractions
+ ; because we don't generate enough random bits.
+ (if (>= n -1152921504606846975)
+ ; Up to 2^60-1, two extractions are enough
+ (let ((q (- (quotient (+ n 1) 1073741824) 1))) ; q=floor(n/2^30)
+ (let loop ()
+ (let ((big (+ (* (internal-random q) 1073741824)
+ (internal-random -1073741824)
+ )
+ ))
+ (if (> big n)
+ big
+ (loop)
+ )
+ )
+ )
+ )
+
+ ; From 2^60 up, we do three extractions.
+ ; The code is better understood if seen as generating three
+ ; digits in base 2^30. q is the maximum value the first digit
+ ; can take. The other digits can take the full range.
+ ;
+ ; The strategy is to generate a random number digit by digit.
+ ; Here's an example in base 10. Say the input n is 348
+ ; (thus requesting a number between 0 and 347). Then the algorithm
+ ; first calls (internal-random 4) to get a digit between 0 and 3,
+ ; then (internal-random 10) twice to get two more digits between
+ ; 0 and 9. Say the result is 366: since it is greater than 347,
+ ; it's discarded and the process restarted. When the result is
+ ; <= 347, that's the returned value. The probability of it being
+ ; greater than the max is always strictly less than 1/2.
+ ;
+ ; This is the same idea but in base 2^30 (1073741824). The
+ ; first digit's weight is (2^30)^2 = 1152921504606846976,
+ ; similarly to how in our base 10 example, the first digit's
+ ; weight is 10^2 = 100. In the base 10 example we first divide
+ ; the target number 348 by 100, taking the ceiling, to get 4.
+ ; Here we divide by (2^30)^2 instead, taking the ceiling too.
+ ;
+ ; The math is a bit obscured by the fact that we generate
+ ; the digits as negative, so that the result is negative as
+ ; well, but it's really the same thing. Changing the sign of
+ ; every digit just changes the sign of the result.
+ ;
+ ; This method works for n up to (2^30)^2*(2^31-1) which is
+ ; 2475880077417839045191401472 (slightly under 91 bits). That
+ ; covers the 64-bit range comfortably, and some more. If larger
+ ; numbers are needed, they'll have to be composed with a
+ ; user-defined procedure.
+
+ (if (>= n -2475880077417839045191401472)
+ (let ((q (- (quotient (+ n 1) 1152921504606846976) 1))) ; q=floor(n/2^60)
+ (let loop ()
+ (let ((big (+ (* (internal-random q) 1152921504606846976)
+ (* (internal-random -1073741824) 1073741824)
+ (internal-random -1073741824)
+ )
+ ))
+ (if (> big n)
+ big
+ (loop)
+ )
+ )
+ )
+ )
+ (error "requested (random n) range too large")
+ )
+ )
+ )
+ )
+)
+
+;(define (rngtest)
+; (display "implementation ")
+; (srand 1)
+; (do
+; ( (n 0 (+ n 1)) )
+; ( (>= n 10000) )
+; (msrg-rand)
+; )
+; (if (= *seed* 399268537)
+; (display "looks correct.")
+; (begin
+; (display "failed.")
+; (newline)
+; (display " current seed ") (display *seed*)
+; (newline)
+; (display " correct seed 399268537")
+; )
+; )
+; (newline)
+;)
+
+
+;This macro defines a while loop which is needed by some older scripts.
+;This is here since it is not defined in R5RS and could be handy to have.
+
+;This while macro was found at:
+;http://www.aracnet.com/~briand/scheme_eval.html
+(define-macro (while test . body)
+ `(let loop ()
+ (cond
+ (,test
+ ,@body
+ (loop)
+ )
+ )
+ )
+)
+
+
+;The following define block(s) require the tsx extension to be loaded
+
+(define (realtime)
+ (car (gettimeofday))
+)
+
+
+;Items below this line are for compatibility with Script-Fu but
+;may be useful enough to keep around
+
+(define (delq item lis)
+ (let ((l '()))
+ (unless (null? lis)
+ (while (pair? lis)
+ (if (<> item (car lis))
+ (set! l (append l (list (car lis))))
+ )
+ (set! lis (cdr lis))
+ )
+ )
+
+ l
+ )
+)
+
+(define (make-list count fill)
+ (vector->list (make-vector count fill))
+)
+
+(define (strbreakup str sep)
+ (let* (
+ (seplen (string-length sep))
+ (start 0)
+ (end (string-length str))
+ (i start)
+ (l '())
+ )
+
+ (if (= seplen 0)
+ (set! l (list str))
+ (begin
+ (while (<= i (- end seplen))
+ (if (substring-equal? sep str i (+ i seplen))
+ (begin
+ (if (= start 0)
+ (set! l (list (substring str start i)))
+ (set! l (append l (list (substring str start i))))
+ )
+ (set! start (+ i seplen))
+ (set! i (+ i seplen -1))
+ )
+ )
+
+ (set! i (+ i 1))
+ )
+
+ (set! l (append l (list (substring str start end))))
+ )
+ )
+
+ l
+ )
+)
+
+(define (string-downcase str)
+ (list->string (map char-downcase (string->list str)))
+)
+
+(define (string-trim str)
+ (string-trim-right (string-trim-left str))
+)
+
+(define (string-trim-left str)
+ (let (
+ (strlen (string-length str))
+ (i 0)
+ )
+
+ (while (and (< i strlen)
+ (char-whitespace? (string-ref str i))
+ )
+ (set! i (+ i 1))
+ )
+
+ (substring str i (string-length str))
+ )
+)
+
+(define (string-trim-right str)
+ (let ((i (- (string-length str) 1)))
+
+ (while (and (>= i 0)
+ (char-whitespace? (string-ref str i))
+ )
+ (set! i (- i 1))
+ )
+
+ (substring str 0 (+ i 1))
+ )
+)
+
+(define (string-upcase str)
+ (list->string (map char-upcase (string->list str)))
+)
+
+(define (substring-equal? str str2 start end)
+ (string=? str (substring str2 start end))
+)
+
+(define (unbreakupstr stringlist sep)
+ (let ((str (car stringlist)))
+
+ (set! stringlist (cdr stringlist))
+ (while (not (null? stringlist))
+ (set! str (string-append str sep (car stringlist)))
+ (set! stringlist (cdr stringlist))
+ )
+
+ str
+ )
+)
+
+
+;Items below this line are deprecated and should not be used in new scripts.
+
+(define aset vector-set!)
+(define aref vector-ref)
+(define fopen open-input-file)
+(define mapcar map)
+(define nil '())
+(define nreverse reverse)
+(define pow expt)
+(define prin1 write)
+
+(define (print obj . port)
+ (apply write obj port)
+ (newline)
+)
+
+(define strcat string-append)
+(define string-lessp string<?)
+(define symbol-bound? defined?)
+(define the-environment current-environment)
+
+(define *pi*
+ (* 4 (atan 1.0))
+)
+
+(define (butlast x)
+ (if (= (length x) 1)
+ '()
+ (reverse (cdr (reverse x)))
+ )
+)
+
+(define (cons-array count type)
+ (case type
+ ((long) (make-vector count 0))
+ ((short) (make-vector count 0))
+ ((byte) (make-vector count 0))
+ ((double) (make-vector count 0.0))
+ ((string) (vector->list (make-vector count "")))
+ (else type)
+ )
+)
+
+(define (fmod a b)
+ (- a (* (truncate (/ a b)) b))
+)
+
+(define (fread arg1 file)
+
+ (define (fread-get-chars count file)
+ (let (
+ (str "")
+ (c 0)
+ )
+
+ (while (> count 0)
+ (set! count (- count 1))
+ (set! c (read-char file))
+ (if (eof-object? c)
+ (set! count 0)
+ (set! str (string-append str (make-string 1 c)))
+ )
+ )
+
+ (if (eof-object? c)
+ ()
+ str
+ )
+ )
+ )
+
+ (if (number? arg1)
+ (begin
+ (set! arg1 (inexact->exact (truncate arg1)))
+ (fread-get-chars arg1 file)
+ )
+ (begin
+ (set! arg1 (fread-get-chars (string-length arg1) file))
+ (string-length arg1)
+ )
+ )
+)
+
+(define (last x)
+ (cons (car (reverse x)) '())
+)
+
+(define (nth k list)
+ (list-ref list k)
+)
+
+(define (prog1 form1 . form2)
+ (let ((a form1))
+ (if (not (null? form2))
+ form2
+ )
+ a
+ )
+)
+
+(define (rand . modulus)
+ (if (null? modulus)
+ (msrg-rand)
+ (apply random modulus)
+ )
+)
+
+(define (strcmp str1 str2)
+ (if (string<? str1 str2)
+ -1
+ (if (string>? str1 str2)
+ 1
+ 0
+ )
+ )
+)
+
+(define (trunc n)
+ (inexact->exact (truncate n))
+)
+
+(define verbose
+ (lambda n
+ (if (or (null? n) (not (number? (car n))))
+ 0
+ (car n)
+ )
+ )
+)
diff --git a/plug-ins/script-fu/scripts/script-fu-set-cmap.scm b/plug-ins/script-fu/scripts/script-fu-set-cmap.scm
new file mode 100644
index 0000000..259d5de
--- /dev/null
+++ b/plug-ins/script-fu/scripts/script-fu-set-cmap.scm
@@ -0,0 +1,64 @@
+; Set Colormap v1.1 September 29, 2004
+; by Kevin Cozens <kcozens@interlog.com>
+;
+; Change the colormap of an image to the colors in a specified palette.
+; Included is script-fu-make-cmap-array (available for use in scripts) which
+; returns an INT8ARRAY containing the colors from a specified palette.
+; This array can be used as the cmap argument for gimp-image-set-colormap.
+
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define (script-fu-make-cmap-array palette)
+ (let* (
+ (num-colors (car (gimp-palette-get-info palette)))
+ (cmap (cons-array (* num-colors 3) 'byte))
+ (color 0)
+ (i 0)
+ )
+
+ (while (< i num-colors)
+ (set! color (car (gimp-palette-entry-get-color palette i)))
+ (aset cmap (* i 3) (car color))
+ (aset cmap (+ (* i 3) 1) (cadr color))
+ (aset cmap (+ (* i 3) 2) (caddr color))
+ (set! i (+ i 1))
+ )
+
+ cmap
+ )
+)
+
+(define (script-fu-set-cmap img drawable palette)
+ (gimp-image-set-colormap img
+ (* (car (gimp-palette-get-info palette)) 3)
+ (script-fu-make-cmap-array palette))
+ (gimp-displays-flush)
+)
+
+(script-fu-register "script-fu-set-cmap"
+ _"Se_t Colormap..."
+ _"Change the colormap of an image to the colors in a specified palette."
+ "Kevin Cozens <kcozens@interlog.com>"
+ "Kevin Cozens"
+ "September 29, 2004"
+ "INDEXED*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-PALETTE _"Palette" "Default"
+)
+
+(script-fu-menu-register "script-fu-set-cmap" "<Image>/Colors/Map/Colormap")
diff --git a/plug-ins/script-fu/scripts/script-fu-util.scm b/plug-ins/script-fu/scripts/script-fu-util.scm
new file mode 100644
index 0000000..a22114d
--- /dev/null
+++ b/plug-ins/script-fu/scripts/script-fu-util.scm
@@ -0,0 +1,94 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+; Resizes the image so as to include the selected layer.
+; The resulting image has the selected layer size.
+; Copyright (C) 2002 Chauk-Mean PROUM
+;
+(define (script-fu-util-image-resize-from-layer image layer)
+ (let* (
+ (width (car (gimp-drawable-width layer)))
+ (height (car (gimp-drawable-height layer)))
+ (posx (- (car (gimp-drawable-offsets layer))))
+ (posy (- (cadr (gimp-drawable-offsets layer))))
+ )
+
+ (gimp-image-resize image width height posx posy)
+ )
+)
+
+; Add the specified layers to the image.
+; The layers will be added in the given order below the
+; active layer.
+;
+(define (script-fu-util-image-add-layers image . layers)
+ (while (not (null? layers))
+ (let ((layer (car layers)))
+ (set! layers (cdr layers))
+ (gimp-image-insert-layer image layer 0 -1)
+ (gimp-image-lower-item image layer)
+ )
+ )
+)
+
+; Allow command line usage of GIMP such as:
+;
+; gimp -i -b '(with-files "*.png" <body>)'
+;
+; where <body> is the code that handles whatever processing you want to
+; perform on the files. There are four variables that are available
+; within the <body>: 'basename', 'image', 'filename' and 'layer'.
+; The 'basename' is the name of the file with its extension removed,
+; while the other three variables are self-explanatory.
+; You basically write your code as though it were processing a single
+; 'image' and the 'with-files' macro applies it to all of the files
+; matching the pattern.
+;
+; For example, to invert the colors of all of the PNG files in the
+; start directory:
+;
+; gimp -i -b '(with-files "*.png" (gimp-drawable-invert layer FALSE) \
+; (gimp-file-save 1 image layer filename filename ))'
+;
+; To do the same thing, but saving them as jpeg instead:
+;
+; gimp -i -b '(with-files "*.png" (gimp-drawable-invert layer FALSE) \
+; (gimp-file-save 1 image layer \
+; (string-append basename ".jpg") \
+; (string-append basename ".jpg") ))'
+
+(define-macro (with-files pattern . body)
+ (let ((loop (gensym))
+ (filenames (gensym))
+ (filename (gensym)))
+ `(begin
+ (let ,loop ((,filenames (cadr (file-glob ,pattern 1))))
+ (unless (null? ,filenames)
+ (let* ((filename (car ,filenames))
+ (image (catch #f (car (gimp-file-load RUN-NONINTERACTIVE
+ filename
+ filename ))))
+ (layer (if image (car (gimp-image-get-active-layer image)) #f))
+ (basename (unbreakupstr (butlast (strbreakup filename ".")) ".")))
+ (when image
+ ,@body
+ (gimp-image-delete image)))
+ (,loop (cdr ,filenames))
+ )
+ )
+ )
+ )
+)
diff --git a/plug-ins/script-fu/scripts/script-fu.init b/plug-ins/script-fu/scripts/script-fu.init
new file mode 100644
index 0000000..d0c9e30
--- /dev/null
+++ b/plug-ins/script-fu/scripts/script-fu.init
@@ -0,0 +1,716 @@
+; Initialization file for TinySCHEME 1.40
+
+; Per R5RS, up to four deep compositions should be defined
+(define (caar x) (car (car x)))
+(define (cadr x) (car (cdr x)))
+(define (cdar x) (cdr (car x)))
+(define (cddr x) (cdr (cdr x)))
+(define (caaar x) (car (car (car x))))
+(define (caadr x) (car (car (cdr x))))
+(define (cadar x) (car (cdr (car x))))
+(define (caddr x) (car (cdr (cdr x))))
+(define (cdaar x) (cdr (car (car x))))
+(define (cdadr x) (cdr (car (cdr x))))
+(define (cddar x) (cdr (cdr (car x))))
+(define (cdddr x) (cdr (cdr (cdr x))))
+(define (caaaar x) (car (car (car (car x)))))
+(define (caaadr x) (car (car (car (cdr x)))))
+(define (caadar x) (car (car (cdr (car x)))))
+(define (caaddr x) (car (car (cdr (cdr x)))))
+(define (cadaar x) (car (cdr (car (car x)))))
+(define (cadadr x) (car (cdr (car (cdr x)))))
+(define (caddar x) (car (cdr (cdr (car x)))))
+(define (cadddr x) (car (cdr (cdr (cdr x)))))
+(define (cdaaar x) (cdr (car (car (car x)))))
+(define (cdaadr x) (cdr (car (car (cdr x)))))
+(define (cdadar x) (cdr (car (cdr (car x)))))
+(define (cdaddr x) (cdr (car (cdr (cdr x)))))
+(define (cddaar x) (cdr (cdr (car (car x)))))
+(define (cddadr x) (cdr (cdr (car (cdr x)))))
+(define (cdddar x) (cdr (cdr (cdr (car x)))))
+(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
+
+;;;; Utility to ease macro creation
+(define (macro-expand form)
+ ((eval (get-closure-code (eval (car form)))) form))
+
+(define (macro-expand-all form)
+ (if (macro? form)
+ (macro-expand-all (macro-expand form))
+ form))
+
+(define *compile-hook* macro-expand-all)
+
+
+(macro (unless form)
+ `(if (not ,(cadr form)) (begin ,@(cddr form))))
+
+(macro (when form)
+ `(if ,(cadr form) (begin ,@(cddr form))))
+
+; DEFINE-MACRO Contributed by Andy Gaynor
+(macro (define-macro dform)
+ (if (symbol? (cadr dform))
+ `(macro ,@(cdr dform))
+ (let ((form (gensym)))
+ `(macro (,(caadr dform) ,form)
+ (apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form))))))
+
+; Utilities for math. Notice that inexact->exact is primitive,
+; but exact->inexact is not.
+(define exact? integer?)
+(define (inexact? x) (and (real? x) (not (integer? x))))
+(define (even? n) (= (remainder n 2) 0))
+(define (odd? n) (not (= (remainder n 2) 0)))
+(define (zero? n) (= n 0))
+(define (positive? n) (> n 0))
+(define (negative? n) (< n 0))
+(define complex? number?)
+(define rational? real?)
+(define (abs n) (if (>= n 0) n (- n)))
+(define (exact->inexact n) (* n 1.0))
+(define (<> n1 n2) (not (= n1 n2)))
+
+; min and max must return inexact if any arg is inexact; use (+ n 0.0)
+(define (max . lst)
+ (foldr (lambda (a b)
+ (if (> a b)
+ (if (exact? b) a (+ a 0.0))
+ (if (exact? a) b (+ b 0.0))))
+ (car lst) (cdr lst)))
+(define (min . lst)
+ (foldr (lambda (a b)
+ (if (< a b)
+ (if (exact? b) a (+ a 0.0))
+ (if (exact? a) b (+ b 0.0))))
+ (car lst) (cdr lst)))
+
+(define (succ x) (+ x 1))
+(define (pred x) (- x 1))
+(define gcd
+ (lambda a
+ (if (null? a)
+ 0
+ (let ((aa (abs (car a)))
+ (bb (abs (cadr a))))
+ (if (= bb 0)
+ aa
+ (gcd bb (remainder aa bb)))))))
+(define lcm
+ (lambda a
+ (if (null? a)
+ 1
+ (let ((aa (abs (car a)))
+ (bb (abs (cadr a))))
+ (if (or (= aa 0) (= bb 0))
+ 0
+ (abs (* (quotient aa (gcd aa bb)) bb)))))))
+
+
+(define (string . charlist)
+ (list->string charlist))
+
+(define (list->string charlist)
+ (let* ((len (length charlist))
+ (newstr (make-string len))
+ (fill-string!
+ (lambda (str i len charlist)
+ (if (= i len)
+ str
+ (begin (string-set! str i (car charlist))
+ (fill-string! str (+ i 1) len (cdr charlist)))))))
+ (fill-string! newstr 0 len charlist)))
+
+(define (string-fill! s e)
+ (let ((n (string-length s)))
+ (let loop ((i 0))
+ (if (= i n)
+ s
+ (begin (string-set! s i e) (loop (succ i)))))))
+
+(define (string->list s)
+ (let loop ((n (pred (string-length s))) (l '()))
+ (if (= n -1)
+ l
+ (loop (pred n) (cons (string-ref s n) l)))))
+
+(define (string-copy str)
+ (string-append str))
+
+(define (string->anyatom str pred)
+ (let* ((a (string->atom str)))
+ (if (pred a) a
+ (error "string->xxx: not a xxx" a))))
+
+(define (string->number str . base)
+ (let ((n (string->atom str (if (null? base) 10 (car base)))))
+ (if (number? n) n #f)))
+
+(define (anyatom->string n pred)
+ (if (pred n)
+ (atom->string n)
+ (error "xxx->string: not a xxx" n)))
+
+
+(define (number->string n . base)
+ (atom->string n (if (null? base) 10 (car base))))
+
+(define (char-cmp? cmp a b)
+ (cmp (char->integer a) (char->integer b)))
+(define (char-ci-cmp? cmp a b)
+ (cmp (char->integer (char-downcase a)) (char->integer (char-downcase b))))
+
+(define (char=? a b) (char-cmp? = a b))
+(define (char<? a b) (char-cmp? < a b))
+(define (char>? a b) (char-cmp? > a b))
+(define (char<=? a b) (char-cmp? <= a b))
+(define (char>=? a b) (char-cmp? >= a b))
+
+(define (char-ci=? a b) (char-ci-cmp? = a b))
+(define (char-ci<? a b) (char-ci-cmp? < a b))
+(define (char-ci>? a b) (char-ci-cmp? > a b))
+(define (char-ci<=? a b) (char-ci-cmp? <= a b))
+(define (char-ci>=? a b) (char-ci-cmp? >= a b))
+
+; Note the trick of returning (cmp x y)
+(define (string-cmp? chcmp cmp a b)
+ (let ((na (string-length a)) (nb (string-length b)))
+ (let loop ((i 0))
+ (cond
+ ((= i na)
+ (if (= i nb) (cmp 0 0) (cmp 0 1)))
+ ((= i nb)
+ (cmp 1 0))
+ ((chcmp = (string-ref a i) (string-ref b i))
+ (loop (succ i)))
+ (else
+ (chcmp cmp (string-ref a i) (string-ref b i)))))))
+
+
+(define (string=? a b) (string-cmp? char-cmp? = a b))
+(define (string<? a b) (string-cmp? char-cmp? < a b))
+(define (string>? a b) (string-cmp? char-cmp? > a b))
+(define (string<=? a b) (string-cmp? char-cmp? <= a b))
+(define (string>=? a b) (string-cmp? char-cmp? >= a b))
+
+(define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b))
+(define (string-ci<? a b) (string-cmp? char-ci-cmp? < a b))
+(define (string-ci>? a b) (string-cmp? char-ci-cmp? > a b))
+(define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b))
+(define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b))
+
+(define (list . x) x)
+
+(define (foldr f x lst)
+ (if (null? lst)
+ x
+ (foldr f (f x (car lst)) (cdr lst))))
+
+(define (unzip1-with-cdr . lists)
+ (unzip1-with-cdr-iterative lists '() '()))
+
+(define (unzip1-with-cdr-iterative lists cars cdrs)
+ (if (null? lists)
+ (cons cars cdrs)
+ (let ((car1 (caar lists))
+ (cdr1 (cdar lists)))
+ (unzip1-with-cdr-iterative
+ (cdr lists)
+ (append cars (list car1))
+ (append cdrs (list cdr1))))))
+
+(define (map proc . lists)
+ (if (null? lists)
+ (apply proc)
+ (if (null? (car lists))
+ '()
+ (let* ((unz (apply unzip1-with-cdr lists))
+ (cars (car unz))
+ (cdrs (cdr unz)))
+ (cons (apply proc cars) (apply map (cons proc cdrs)))))))
+
+(define (for-each proc . lists)
+ (if (null? lists)
+ (apply proc)
+ (if (null? (car lists))
+ #t
+ (let* ((unz (apply unzip1-with-cdr lists))
+ (cars (car unz))
+ (cdrs (cdr unz)))
+ (apply proc cars) (apply map (cons proc cdrs))))))
+
+(define (list-tail x k)
+ (if (zero? k)
+ x
+ (list-tail (cdr x) (- k 1))))
+
+(define (list-ref x k)
+ (car (list-tail x k)))
+
+(define (last-pair x)
+ (if (pair? (cdr x))
+ (last-pair (cdr x))
+ x))
+
+(define (head stream) (car stream))
+
+(define (tail stream) (force (cdr stream)))
+
+(define (vector-equal? x y)
+ (and (vector? x) (vector? y) (= (vector-length x) (vector-length y))
+ (let ((n (vector-length x)))
+ (let loop ((i 0))
+ (if (= i n)
+ #t
+ (and (equal? (vector-ref x i) (vector-ref y i))
+ (loop (succ i))))))))
+
+(define (list->vector x)
+ (apply vector x))
+
+(define (vector-fill! v e)
+ (let ((n (vector-length v)))
+ (let loop ((i 0))
+ (if (= i n)
+ v
+ (begin (vector-set! v i e) (loop (succ i)))))))
+
+(define (vector->list v)
+ (let loop ((n (pred (vector-length v))) (l '()))
+ (if (= n -1)
+ l
+ (loop (pred n) (cons (vector-ref v n) l)))))
+
+;; The following quasiquote macro is due to Eric S. Tiedemann.
+;; Copyright 1988 by Eric S. Tiedemann; all rights reserved.
+;;
+;; Subsequently modified to handle vectors: D. Souflis
+
+(macro
+ quasiquote
+ (lambda (l)
+ (define (mcons f l r)
+ (if (and (pair? r)
+ (eq? (car r) 'quote)
+ (eq? (car (cdr r)) (cdr f))
+ (pair? l)
+ (eq? (car l) 'quote)
+ (eq? (car (cdr l)) (car f)))
+ (if (or (procedure? f) (number? f) (string? f))
+ f
+ (list 'quote f))
+ (if (eqv? l vector)
+ (apply l (eval r))
+ (list 'cons l r)
+ )))
+ (define (mappend f l r)
+ (if (or (null? (cdr f))
+ (and (pair? r)
+ (eq? (car r) 'quote)
+ (eq? (car (cdr r)) '())))
+ l
+ (list 'append l r)))
+ (define (foo level form)
+ (cond ((not (pair? form))
+ (if (or (procedure? form) (number? form) (string? form))
+ form
+ (list 'quote form))
+ )
+ ((eq? 'quasiquote (car form))
+ (mcons form ''quasiquote (foo (+ level 1) (cdr form))))
+ (#t (if (zero? level)
+ (cond ((eq? (car form) 'unquote) (car (cdr form)))
+ ((eq? (car form) 'unquote-splicing)
+ (error "Unquote-splicing wasn't in a list:"
+ form))
+ ((and (pair? (car form))
+ (eq? (car (car form)) 'unquote-splicing))
+ (mappend form (car (cdr (car form)))
+ (foo level (cdr form))))
+ (#t (mcons form (foo level (car form))
+ (foo level (cdr form)))))
+ (cond ((eq? (car form) 'unquote)
+ (mcons form ''unquote (foo (- level 1)
+ (cdr form))))
+ ((eq? (car form) 'unquote-splicing)
+ (mcons form ''unquote-splicing
+ (foo (- level 1) (cdr form))))
+ (#t (mcons form (foo level (car form))
+ (foo level (cdr form)))))))))
+ (foo 0 (car (cdr l)))))
+
+;;;;;Helper for the dynamic-wind definition. By Tom Breton (Tehom)
+(define (shared-tail x y)
+ (let ((len-x (length x))
+ (len-y (length y)))
+ (define (shared-tail-helper x y)
+ (if
+ (eq? x y)
+ x
+ (shared-tail-helper (cdr x) (cdr y))))
+
+ (cond
+ ((> len-x len-y)
+ (shared-tail-helper
+ (list-tail x (- len-x len-y))
+ y))
+ ((< len-x len-y)
+ (shared-tail-helper
+ x
+ (list-tail y (- len-y len-x))))
+ (#t (shared-tail-helper x y)))))
+
+;;;;;Dynamic-wind by Tom Breton (Tehom)
+
+;;Guarded because we must only eval this once, because doing so
+;;redefines call/cc in terms of old call/cc
+(unless (defined? 'dynamic-wind)
+ (let
+ ;;These functions are defined in the context of a private list of
+ ;;pairs of before/after procs.
+ ( (*active-windings* '())
+ ;;We'll define some functions into the larger environment, so
+ ;;we need to know it.
+ (outer-env (current-environment)))
+
+ ;;Poor-man's structure operations
+ (define before-func car)
+ (define after-func cdr)
+ (define make-winding cons)
+
+ ;;Manage active windings
+ (define (activate-winding! new)
+ ((before-func new))
+ (set! *active-windings* (cons new *active-windings*)))
+ (define (deactivate-top-winding!)
+ (let ((old-top (car *active-windings*)))
+ ;;Remove it from the list first so it's not active during its
+ ;;own exit.
+ (set! *active-windings* (cdr *active-windings*))
+ ((after-func old-top))))
+
+ (define (set-active-windings! new-ws)
+ (unless (eq? new-ws *active-windings*)
+ (let ((shared (shared-tail new-ws *active-windings*)))
+
+ ;;Define the looping functions.
+ ;;Exit the old list. Do deeper ones last. Don't do
+ ;;any shared ones.
+ (define (pop-many)
+ (unless (eq? *active-windings* shared)
+ (deactivate-top-winding!)
+ (pop-many)))
+ ;;Enter the new list. Do deeper ones first so that the
+ ;;deeper windings will already be active. Don't do any
+ ;;shared ones.
+ (define (push-many new-ws)
+ (unless (eq? new-ws shared)
+ (push-many (cdr new-ws))
+ (activate-winding! (car new-ws))))
+
+ ;;Do it.
+ (pop-many)
+ (push-many new-ws))))
+
+ ;;The definitions themselves.
+ (eval
+ `(define call-with-current-continuation
+ ;;It internally uses the built-in call/cc, so capture it.
+ ,(let ((old-c/cc call-with-current-continuation))
+ (lambda (func)
+ ;;Use old call/cc to get the continuation.
+ (old-c/cc
+ (lambda (continuation)
+ ;;Call func with not the continuation itself
+ ;;but a procedure that adjusts the active
+ ;;windings to what they were when we made
+ ;;this, and only then calls the
+ ;;continuation.
+ (func
+ (let ((current-ws *active-windings*))
+ (lambda (x)
+ (set-active-windings! current-ws)
+ (continuation x)))))))))
+ outer-env)
+ ;;We can't just say "define (dynamic-wind before thunk after)"
+ ;;because the lambda it's defined to lives in this environment,
+ ;;not in the global environment.
+ (eval
+ `(define dynamic-wind
+ ,(lambda (before thunk after)
+ ;;Make a new winding
+ (activate-winding! (make-winding before after))
+ (let ((result (thunk)))
+ ;;Get rid of the new winding.
+ (deactivate-top-winding!)
+ ;;The return value is that of thunk.
+ result)))
+ outer-env)))
+
+(define call/cc call-with-current-continuation)
+
+
+;;;;; atom? and equal? written by a.k
+
+;;;; atom?
+(define (atom? x)
+ (not (pair? x)))
+
+;;;; equal?
+(define (equal? x y)
+ (cond
+ ((pair? x)
+ (and (pair? y)
+ (equal? (car x) (car y))
+ (equal? (cdr x) (cdr y))))
+ ((vector? x)
+ (and (vector? y) (vector-equal? x y)))
+ ((string? x)
+ (and (string? y) (string=? x y)))
+ (else (eqv? x y))))
+
+;;;; (do ((var init inc) ...) (endtest result ...) body ...)
+;;
+(macro do
+ (lambda (do-macro)
+ (apply (lambda (do vars endtest . body)
+ (let ((do-loop (gensym)))
+ `(letrec ((,do-loop
+ (lambda ,(map (lambda (x)
+ (if (pair? x) (car x) x))
+ `,vars)
+ (if ,(car endtest)
+ (begin ,@(cdr endtest))
+ (begin
+ ,@body
+ (,do-loop
+ ,@(map (lambda (x)
+ (cond
+ ((not (pair? x)) x)
+ ((< (length x) 3) (car x))
+ (else (car (cdr (cdr x))))))
+ `,vars)))))))
+ (,do-loop
+ ,@(map (lambda (x)
+ (if (and (pair? x) (cdr x))
+ (car (cdr x))
+ '()))
+ `,vars)))))
+ do-macro)))
+
+;;;; generic-member
+(define (generic-member cmp obj lst)
+ (cond
+ ((null? lst) #f)
+ ((cmp obj (car lst)) lst)
+ (else (generic-member cmp obj (cdr lst)))))
+
+(define (memq obj lst)
+ (generic-member eq? obj lst))
+(define (memv obj lst)
+ (generic-member eqv? obj lst))
+(define (member obj lst)
+ (generic-member equal? obj lst))
+
+;;;; generic-assoc
+(define (generic-assoc cmp obj alst)
+ (cond
+ ((null? alst) #f)
+ ((cmp obj (caar alst)) (car alst))
+ (else (generic-assoc cmp obj (cdr alst)))))
+
+(define (assq obj alst)
+ (generic-assoc eq? obj alst))
+(define (assv obj alst)
+ (generic-assoc eqv? obj alst))
+(define (assoc obj alst)
+ (generic-assoc equal? obj alst))
+
+(define (acons x y z) (cons (cons x y) z))
+
+;;;; Handy for imperative programs
+;;;; Used as: (define-with-return (foo x y) .... (return z) ...)
+(macro (define-with-return form)
+ `(define ,(cadr form)
+ (call/cc (lambda (return) ,@(cddr form)))))
+
+;;;; Simple exception handling
+;
+; Exceptions are caught as follows:
+;
+; (catch (do-something to-recover and-return meaningful-value)
+; (if-something goes-wrong)
+; (with-these calls))
+;
+; "Catch" establishes a scope spanning multiple call-frames
+; until another "catch" is encountered.
+;
+; Exceptions are thrown with:
+;
+; (throw "message")
+;
+; If used outside a (catch ...), reverts to (error "message)
+
+(define *handlers* (list))
+
+(define (push-handler proc)
+ (set! *handlers* (cons proc *handlers*)))
+
+(define (pop-handler)
+ (let ((h (car *handlers*)))
+ (set! *handlers* (cdr *handlers*))
+ h))
+
+(define (more-handlers?)
+ (pair? *handlers*))
+
+(define (throw . x)
+ (if (more-handlers?)
+ (apply (pop-handler))
+ (apply error x)))
+
+(macro (catch form)
+ (let ((label (gensym)))
+ `(call/cc (lambda (exit)
+ (push-handler (lambda () (exit ,(cadr form))))
+ (let ((,label (begin ,@(cddr form))))
+ (pop-handler)
+ ,label)))))
+
+(define *error-hook* throw)
+
+
+;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL
+
+(macro (make-environment form)
+ `(apply (lambda ()
+ ,@(cdr form)
+ (current-environment))))
+
+(define-macro (eval-polymorphic x . envl)
+ (display envl)
+ (let* ((env (if (null? envl) (current-environment) (eval (car envl))))
+ (xval (eval x env)))
+ (if (closure? xval)
+ (make-closure (get-closure-code xval) env)
+ xval)))
+
+; Redefine this if you install another package infrastructure
+; Also redefine 'package'
+(define *colon-hook* eval)
+
+;;;;; I/O
+
+(define (input-output-port? p)
+ (and (input-port? p) (output-port? p)))
+
+(define (close-port p)
+ (cond
+ ((input-output-port? p) (close-input-port p) (close-output-port p))
+ ((input-port? p) (close-input-port p))
+ ((output-port? p) (close-output-port p))
+ (else (throw "Not a port" p))))
+
+(define (call-with-input-file s p)
+ (let ((inport (open-input-file s)))
+ (if (eq? inport #f)
+ #f
+ (let ((res (p inport)))
+ (close-input-port inport)
+ res))))
+
+(define (call-with-output-file s p)
+ (let ((outport (open-output-file s)))
+ (if (eq? outport #f)
+ #f
+ (let ((res (p outport)))
+ (close-output-port outport)
+ res))))
+
+(define (with-input-from-file s p)
+ (let ((inport (open-input-file s)))
+ (if (eq? inport #f)
+ #f
+ (let ((prev-inport (current-input-port)))
+ (set-input-port inport)
+ (let ((res (p)))
+ (close-input-port inport)
+ (set-input-port prev-inport)
+ res)))))
+
+(define (with-output-to-file s p)
+ (let ((outport (open-output-file s)))
+ (if (eq? outport #f)
+ #f
+ (let ((prev-outport (current-output-port)))
+ (set-output-port outport)
+ (let ((res (p)))
+ (close-output-port outport)
+ (set-output-port prev-outport)
+ res)))))
+
+(define (with-input-output-from-to-files si so p)
+ (let ((inport (open-input-file si))
+ (outport (open-input-file so)))
+ (if (not (and inport outport))
+ (begin
+ (close-input-port inport)
+ (close-output-port outport)
+ #f)
+ (let ((prev-inport (current-input-port))
+ (prev-outport (current-output-port)))
+ (set-input-port inport)
+ (set-output-port outport)
+ (let ((res (p)))
+ (close-input-port inport)
+ (close-output-port outport)
+ (set-input-port prev-inport)
+ (set-output-port prev-outport)
+ res)))))
+
+; Random number generator (maximum cycle)
+(define *seed* 1)
+(define (random-next)
+ (let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a)))
+ (set! *seed*
+ (- (* a (- *seed*
+ (* (quotient *seed* q) q)))
+ (* (quotient *seed* q) r)))
+ (if (< *seed* 0) (set! *seed* (+ *seed* m)))
+ *seed*))
+;; SRFI-0
+;; COND-EXPAND
+;; Implemented as a macro
+(define *features* '(srfi-0 tinyscheme))
+
+(define-macro (cond-expand . cond-action-list)
+ (cond-expand-runtime cond-action-list))
+
+(define (cond-expand-runtime cond-action-list)
+ (if (null? cond-action-list)
+ #t
+ (if (cond-eval (caar cond-action-list))
+ `(begin ,@(cdar cond-action-list))
+ (cond-expand-runtime (cdr cond-action-list)))))
+
+(define (cond-eval-and cond-list)
+ (foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list))
+
+(define (cond-eval-or cond-list)
+ (foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list))
+
+(define (cond-eval condition)
+ (cond
+ ((symbol? condition)
+ (if (member condition *features*) #t #f))
+ ((eq? condition #t) #t)
+ ((eq? condition #f) #f)
+ (else (case (car condition)
+ ((and) (cond-eval-and (cdr condition)))
+ ((or) (cond-eval-or (cdr condition)))
+ ((not) (if (not (null? (cddr condition)))
+ (error "cond-expand : 'not' takes 1 argument")
+ (not (cond-eval (cadr condition)))))
+ (else (error "cond-expand : unknown operator" (car condition)))))))
+
+(gc-verbose #f)
diff --git a/plug-ins/script-fu/scripts/select-to-brush.scm b/plug-ins/script-fu/scripts/select-to-brush.scm
new file mode 100644
index 0000000..79f0bed
--- /dev/null
+++ b/plug-ins/script-fu/scripts/select-to-brush.scm
@@ -0,0 +1,144 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Selection-to-brush
+; Copyright (c) 1997 Adrian Likins
+; aklikins@eos.ncsu.edu
+;
+; Takes the current selection, saves it as a brush, and makes it the
+; active brush..
+;
+; Parts of this script from Sven Neuman's Drop-Shadow and
+; Seth Burgess's mkbrush scripts.
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-selection-to-brush image
+ drawable
+ name
+ filename
+ spacing)
+ (let* (
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (selection-bounds (gimp-selection-bounds image))
+ (select-offset-x (cadr selection-bounds))
+ (select-offset-y (caddr selection-bounds))
+ (selection-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (selection-height (- (caddr (cddr selection-bounds)) select-offset-y))
+ (from-selection 0)
+ (active-selection 0)
+ (brush-draw-type 0)
+ (brush-image-type 0)
+ (brush-image 0)
+ (brush-draw 0)
+ (filename2 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable image)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! from-selection FALSE)
+ )
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))
+ )
+ )
+
+ (gimp-edit-copy drawable)
+
+ (set! brush-draw-type
+ (if (= type GRAYA-IMAGE)
+ GRAY-IMAGE
+ RGBA-IMAGE))
+
+ (set! brush-image-type
+ (if (= type GRAYA-IMAGE)
+ GRAY
+ RGB))
+
+ (set! brush-image (car (gimp-image-new selection-width
+ selection-height
+ brush-image-type)))
+
+ (set! brush-draw
+ (car (gimp-layer-new brush-image
+ selection-width
+ selection-height
+ brush-draw-type
+ "Brush"
+ 100
+ LAYER-MODE-NORMAL)))
+
+ (gimp-image-insert-layer brush-image brush-draw 0 0)
+
+ (gimp-selection-none brush-image)
+
+ (if (= type GRAYA-IMAGE)
+ (begin
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-fill brush-draw FILL-BACKGROUND))
+ (gimp-drawable-fill brush-draw FILL-TRANSPARENT)
+ )
+
+ (let ((floating-sel (car (gimp-edit-paste brush-draw FALSE))))
+ (gimp-floating-sel-anchor floating-sel)
+ )
+
+ (set! filename2 (string-append gimp-directory
+ "/brushes/"
+ filename
+ (number->string image)
+ ".gbr"))
+
+ (file-gbr-save 1 brush-image brush-draw filename2 filename2 spacing name)
+
+ (if (= from-selection TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-image-remove-channel image active-selection)
+ )
+ )
+
+ (gimp-image-undo-enable image)
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-delete brush-image)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+
+ (gimp-brushes-refresh)
+ (gimp-context-set-brush name)
+ )
+)
+
+(script-fu-register "script-fu-selection-to-brush"
+ _"To _Brush..."
+ _"Convert a selection to a brush"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "10/07/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-STRING _"_Brush name" "My Brush"
+ SF-STRING _"_File name" "mybrush"
+ SF-ADJUSTMENT _"_Spacing" '(25 0 1000 1 1 1 0)
+)
diff --git a/plug-ins/script-fu/scripts/select-to-image.scm b/plug-ins/script-fu/scripts/select-to-image.scm
new file mode 100644
index 0000000..dec088d
--- /dev/null
+++ b/plug-ins/script-fu/scripts/select-to-image.scm
@@ -0,0 +1,89 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Selection to Image
+; Copyright (c) 1997 Adrian Likins
+; aklikins@eos.ncsu.edu
+;
+; Takes the Current selection and saves it as a separate image.
+;
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-selection-to-image image drawable)
+ (let* (
+ (draw-type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-type (car (gimp-image-base-type image)))
+ (selection-bounds (gimp-selection-bounds image))
+ (select-offset-x (cadr selection-bounds))
+ (select-offset-y (caddr selection-bounds))
+ (selection-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (selection-height (- (caddr (cddr selection-bounds)) select-offset-y))
+ (active-selection 0)
+ (from-selection 0)
+ (new-image 0)
+ (new-draw 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable image)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! active-selection (car (gimp-selection-save image)))
+ (set! from-selection FALSE)
+ )
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))
+ )
+ )
+
+ (gimp-edit-copy drawable)
+
+ (set! new-image (car (gimp-image-new selection-width
+ selection-height image-type)))
+ (set! new-draw (car (gimp-layer-new new-image
+ selection-width selection-height
+ draw-type "Selection" 100 LAYER-MODE-NORMAL)))
+ (gimp-image-insert-layer new-image new-draw 0 0)
+ (gimp-drawable-fill new-draw FILL-BACKGROUND)
+
+ (let ((floating-sel (car (gimp-edit-paste new-draw FALSE))))
+ (gimp-floating-sel-anchor floating-sel)
+ )
+
+ (gimp-image-undo-enable image)
+ (gimp-image-set-active-layer image drawable)
+ (gimp-display-new new-image)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-selection-to-image"
+ _"To _Image"
+ _"Convert a selection to an image"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "10/07/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+)
diff --git a/plug-ins/script-fu/scripts/select-to-pattern.scm b/plug-ins/script-fu/scripts/select-to-pattern.scm
new file mode 100644
index 0000000..6b2f9eb
--- /dev/null
+++ b/plug-ins/script-fu/scripts/select-to-pattern.scm
@@ -0,0 +1,103 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Based on select-to-brush by
+; Copyright (c) 1997 Adrian Likins aklikins@eos.ncsu.edu
+; Author Cameron Gregory, http://www.flamingtext.com/
+;
+; Takes the current selection, saves it as a pattern and makes it the active
+; pattern
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-selection-to-pattern image drawable desc filename)
+
+ (let* (
+ (selection-width 0)
+ (selection-height 0)
+ (selection-bounds 0)
+ (select-offset-x 0)
+ (select-offset-y 0)
+ (pattern-draw-type 0)
+ (pattern-image-type 0)
+ (pattern-image 0)
+ (pattern-draw 0)
+ (filename2 0)
+ )
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (set! selection-width (car (gimp-drawable-width drawable)))
+ (set! selection-height (car (gimp-drawable-height drawable)))
+ )
+ (begin
+ (set! selection-bounds (gimp-drawable-mask-bounds drawable))
+ (set! select-offset-x (cadr selection-bounds))
+ (set! select-offset-y (caddr selection-bounds))
+ (set! selection-width (- (cadr (cddr selection-bounds)) select-offset-x))
+ (set! selection-height (- (caddr (cddr selection-bounds)) select-offset-y))
+ )
+ )
+
+ (if (= (car (gimp-drawable-has-alpha drawable)) TRUE)
+ (set! pattern-draw-type RGBA-IMAGE)
+ (set! pattern-draw-type RGB-IMAGE)
+ )
+
+ (set! pattern-image-type RGB)
+
+ (set! pattern-image (car (gimp-image-new selection-width selection-height
+ pattern-image-type)))
+
+ (set! pattern-draw
+ (car (gimp-layer-new pattern-image selection-width selection-height
+ pattern-draw-type "Pattern" 100 LAYER-MODE-NORMAL)))
+
+ (gimp-drawable-fill pattern-draw FILL-TRANSPARENT)
+
+ (gimp-image-insert-layer pattern-image pattern-draw 0 0)
+
+ (gimp-edit-copy drawable)
+
+ (let ((floating-sel (car (gimp-edit-paste pattern-draw FALSE))))
+ (gimp-floating-sel-anchor floating-sel))
+
+ (set! filename2 (string-append gimp-directory
+ "/patterns/"
+ filename
+ (number->string image)
+ ".pat"))
+
+ (file-pat-save 1 pattern-image pattern-draw filename2 "" desc)
+ (gimp-patterns-refresh)
+ (gimp-context-set-pattern desc)
+
+ (gimp-image-delete pattern-image)
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-selection-to-pattern"
+ _"To _Pattern..."
+ _"Convert a selection to a pattern"
+ "Cameron Gregory <cameron@bloke.com>"
+ "Cameron Gregory"
+ "09/02/2003"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-STRING _"_Pattern name" "My Pattern"
+ SF-STRING _"_File name" "mypattern"
+)
diff --git a/plug-ins/script-fu/scripts/selection-round.scm b/plug-ins/script-fu/scripts/selection-round.scm
new file mode 100644
index 0000000..afbc91c
--- /dev/null
+++ b/plug-ins/script-fu/scripts/selection-round.scm
@@ -0,0 +1,164 @@
+; selection-rounded-rectangle.scm -*-scheme-*-
+
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+; CHANGE-LOG:
+; 1.00 - initial release
+; 1.01 - some code cleanup, no real changes
+; 1.02 - made script undoable
+
+; 2.00 - ALAN's Branch. changed name, menu, location, and description
+; 2.01 - fixed to work if there was no current selection.
+; 2.02 - changed scale to percentages, usability tweaking.
+; 2.10 - added concave round edges, updated description.
+; 2.11 - tweeked description, changed comments, relinquished any rights.
+
+; Copyright (C) 1997, 1998, Sven Neumann
+; Copyright (C) 2004, Alan Horkan.
+; Alan Horkan relinquishes all rights to his changes,
+; full ownership of this script belongs to Sven Neumann.
+
+(define (script-fu-selection-rounded-rectangle image drawable radius concave)
+ (gimp-image-undo-group-start image)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE) (gimp-selection-all image))
+ (let* (
+ (radius (/ radius 100)) ; convert from percentages
+ (radius (min radius 1.0))
+ (radius (max radius 0.0))
+ (select-bounds (gimp-selection-bounds image))
+ (has-selection (car select-bounds))
+ (select-x1 (cadr select-bounds))
+ (select-y1 (caddr select-bounds))
+ (select-x2 (cadr (cddr select-bounds)))
+ (select-y2 (caddr (cddr select-bounds)))
+ (select-width (- select-x2 select-x1))
+ (select-height (- select-y2 select-y1))
+ (cut-radius 0)
+ (ellipse-radius 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ ;; select to the full bounds of the selection,
+ ;; fills in irregular shapes or holes.
+ (gimp-image-select-rectangle image CHANNEL-OP-ADD
+ select-x1 select-y1 select-width select-height)
+
+ (if (> select-width select-height)
+ (set! cut-radius (trunc (+ 1 (* radius (/ select-height 2)))))
+ (set! cut-radius (trunc (+ 1 (* radius (/ select-width 2)))))
+ )
+ (set! ellipse-radius (* cut-radius 2))
+
+ (gimp-context-set-antialias TRUE)
+ ;; cut away rounded (concave) corners
+ ; top right
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT
+ (- select-x1 cut-radius)
+ (- select-y1 cut-radius)
+ (* cut-radius 2)
+ (* cut-radius 2))
+ ; lower left
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT
+ (- select-x1 cut-radius)
+ (- select-y2 cut-radius)
+ (* cut-radius 2)
+ (* cut-radius 2))
+ ; top right
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT
+ (- select-x2 cut-radius)
+ (- select-y1 cut-radius)
+ (* cut-radius 2)
+ (* cut-radius 2))
+ ; bottom left
+ (gimp-image-select-ellipse image CHANNEL-OP-SUBTRACT
+ (- select-x2 cut-radius)
+ (- select-y2 cut-radius)
+ (* cut-radius 2)
+ (* cut-radius 2))
+
+ ;; add in rounded (convex) corners
+ (if (= concave FALSE)
+ (begin
+ (gimp-image-select-ellipse image
+ CHANNEL-OP-ADD
+ select-x1
+ select-y1
+ ellipse-radius
+ ellipse-radius)
+ (gimp-image-select-ellipse image
+ CHANNEL-OP-ADD
+ select-x1
+ (- select-y2 ellipse-radius)
+ ellipse-radius
+ ellipse-radius)
+ (gimp-image-select-ellipse image
+ CHANNEL-OP-ADD
+ (- select-x2 ellipse-radius)
+ select-y1
+ ellipse-radius
+ ellipse-radius)
+ (gimp-image-select-ellipse image
+ CHANNEL-OP-ADD
+ (- select-x2 ellipse-radius)
+ (- select-y2 ellipse-radius)
+ ellipse-radius
+ ellipse-radius)
+ )
+ )
+
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+ (gimp-context-pop)
+ )
+)
+
+
+(define (script-fu-selection-round image drawable radius)
+ (script-fu-selection-rounded-rectangle image drawable (* radius 100) FALSE)
+)
+
+
+(script-fu-register "script-fu-selection-rounded-rectangle"
+ _"Rounded R_ectangle..."
+ _"Round the corners of the current selection"
+ "Alan Horkan, Sven Neumann" ; authors
+ "Sven Neumann" ; copyright
+ "2004/06/07"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"R_adius (%)" '(50 0 100 1 10 0 0)
+ SF-TOGGLE _"Co_ncave" FALSE
+)
+
+(script-fu-register "script-fu-selection-round"
+ ""
+ "This procedure is deprecated! Use 'script-fu-selection-rounded-rectangle' instead."
+ "Sven Neumann" ; authors
+ "Sven Neumann" ; copyright
+ "1998/02/06"
+ "*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT "Relative radius" '(1 0 128 0.1 1 1 1)
+)
+
+(script-fu-menu-register "script-fu-selection-rounded-rectangle"
+ "<Image>/Select/Modify")
diff --git a/plug-ins/script-fu/scripts/slide.scm b/plug-ins/script-fu/scripts/slide.scm
new file mode 100644
index 0000000..4889d62
--- /dev/null
+++ b/plug-ins/script-fu/scripts/slide.scm
@@ -0,0 +1,261 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; slide.scm version 0.41 2004/03/28
+;
+; CHANGE-LOG:
+; 0.20 - first public release
+; 0.30 - some code cleanup
+; now uses the rotate plug-in to improve speed
+; 0.40 - changes to work with gimp-1.1
+; if the image was rotated, rotate the whole thing back when finished
+; 0.41 - changes to work with gimp-2.0, slightly correct text offsets,
+; Nils Philippsen <nphilipp@redhat.com> 2004/03/28
+;
+; !still in development!
+; TODO: - change the script so that the film is rotated, not the image
+; - antialiasing
+; - make 'add background' an option
+; - ?
+;
+; Copyright (C) 1997-1999 Sven Neumann <sven@gimp.org>
+;
+; makes your picture look like a slide
+;
+; The script works on RGB and grayscale images that contain only
+; one layer. The image is cropped to fit into an aspect ratio of 1:1,5.
+; It creates a copy of the image or can optionally work on the original.
+; The script uses the current background color to create a background
+; layer.
+
+
+(define (script-fu-slide img
+ drawable
+ text
+ number
+ fontname
+ font-color
+ work-on-copy)
+
+ (define (crop width height ratio)
+ (if (>= width (* ratio height))
+ (* ratio height)
+ width
+ )
+ )
+
+ (let* (
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image (cond ((= work-on-copy TRUE)
+ (car (gimp-image-duplicate img)))
+ ((= work-on-copy FALSE)
+ img)))
+ (owidth (car (gimp-image-width image)))
+ (oheight (car (gimp-image-height image)))
+ (ratio (if (>= owidth oheight) (/ 3 2)
+ (/ 2 3)))
+ (crop-width (crop owidth oheight ratio))
+ (crop-height (/ crop-width ratio))
+ (width (* (max crop-width crop-height) 1.05))
+ (height (* (min crop-width crop-height) 1.5))
+ (hole-width (/ width 20))
+ (hole-space (/ width 8))
+ (hole-height (/ width 12))
+ (hole-radius (/ hole-width 4))
+ (hole-start (- (/ (rand 1000) 1000) 0.5))
+ (film-layer (car (gimp-layer-new image
+ width
+ height
+ type
+ "Film"
+ 100
+ LAYER-MODE-NORMAL)))
+ (bg-layer (car (gimp-layer-new image
+ width
+ height
+ type
+ "Background"
+ 100
+ LAYER-MODE-NORMAL)))
+ (pic-layer (car (gimp-image-get-active-drawable image)))
+ (numbera (string-append number "A"))
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+ (gimp-context-set-feather FALSE)
+
+ (if (= work-on-copy TRUE)
+ (gimp-image-undo-disable image)
+ (gimp-image-undo-group-start image)
+ )
+
+; add an alpha channel to the image
+ (gimp-layer-add-alpha pic-layer)
+
+; crop, resize and eventually rotate the image
+ (gimp-image-crop image
+ crop-width
+ crop-height
+ (/ (- owidth crop-width) 2)
+ (/ (- oheight crop-height) 2))
+ (gimp-image-resize image
+ width
+ height
+ (/ (- width crop-width) 2)
+ (/ (- height crop-height) 2))
+ (if (< ratio 1)
+ (plug-in-rotate RUN-NONINTERACTIVE image pic-layer 1 FALSE)
+ )
+
+; add the background layer
+ (gimp-drawable-fill bg-layer FILL-BACKGROUND)
+ (gimp-image-insert-layer image bg-layer 0 -1)
+
+; add the film layer
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-fill film-layer FILL-BACKGROUND)
+ (gimp-image-insert-layer image film-layer 0 -1)
+
+; add the text
+ (gimp-context-set-foreground font-color)
+ (gimp-floating-sel-anchor (car (gimp-text-fontname image
+ film-layer
+ (+ hole-start (* -0.25 width))
+ (* 0.01 height)
+ text
+ 0
+ TRUE
+ (* 0.040 height) PIXELS fontname)))
+ (gimp-floating-sel-anchor (car (gimp-text-fontname image
+ film-layer
+ (+ hole-start (* 0.75 width))
+ (* 0.01 height)
+ text
+ 0
+ TRUE
+ (* 0.040 height) PIXELS
+ fontname )))
+ (gimp-floating-sel-anchor (car (gimp-text-fontname image
+ film-layer
+ (+ hole-start (* 0.35 width))
+ 0.0
+ number
+ 0
+ TRUE
+ (* 0.050 height) PIXELS
+ fontname )))
+ (gimp-floating-sel-anchor (car (gimp-text-fontname image
+ film-layer
+ (+ hole-start (* 0.35 width))
+ (* 0.94 height)
+ number
+ 0
+ TRUE
+ (* 0.050 height) PIXELS
+ fontname )))
+ (gimp-floating-sel-anchor (car (gimp-text-fontname image
+ film-layer
+ (+ hole-start (* 0.85 width))
+ (* 0.945 height)
+ numbera
+ 0
+ TRUE
+ (* 0.045 height) PIXELS
+ fontname )))
+
+; create a mask for the holes and cut them out
+ (let* (
+ (film-mask (car (gimp-layer-create-mask film-layer ADD-MASK-WHITE)))
+ (hole hole-start)
+ (top-y (* height 0.06))
+ (bottom-y (* height 0.855))
+ )
+
+ (gimp-layer-add-mask film-layer film-mask)
+
+ (gimp-selection-none image)
+ (while (< hole 8)
+ (gimp-image-select-rectangle image
+ CHANNEL-OP-ADD
+ (* hole-space hole)
+ top-y
+ hole-width
+ hole-height)
+ (gimp-image-select-rectangle image
+ CHANNEL-OP-ADD
+ (* hole-space hole)
+ bottom-y
+ hole-width
+ hole-height)
+ (set! hole (+ hole 1))
+ )
+
+ (gimp-context-set-foreground '(0 0 0))
+ (gimp-drawable-edit-fill film-mask FILL-BACKGROUND)
+ (gimp-selection-none image)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE image film-mask hole-radius TRUE TRUE)
+ (gimp-threshold film-mask 127 255)
+
+ (gimp-layer-remove-mask film-layer MASK-APPLY)
+ )
+
+; reorder the layers
+ (gimp-image-raise-item image pic-layer)
+ (gimp-image-raise-item image pic-layer)
+
+; eventually rotate the whole thing back
+ (if (< ratio 1)
+ (plug-in-rotate RUN-NONINTERACTIVE image pic-layer 3 TRUE)
+ )
+
+; clean up after the script
+ (gimp-selection-none image)
+
+ (if (= work-on-copy TRUE)
+ (begin
+ (gimp-display-new image)
+ (gimp-image-undo-enable image)
+ )
+ (gimp-image-undo-group-end image)
+ )
+
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-slide"
+ _"_Slide..."
+ _"Add a slide-film like frame, sprocket holes, and labels to an image"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "2004/03/28"
+ "RGB GRAY"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-STRING _"Text" "GIMP"
+ SF-STRING _"Number" "32"
+ SF-FONT _"Font" "Serif"
+ SF-COLOR _"Font color" '(255 180 0)
+ SF-TOGGLE _"Work on copy" TRUE
+)
+
+(script-fu-menu-register "script-fu-slide"
+ "<Image>/Filters/Decor")
diff --git a/plug-ins/script-fu/scripts/spinning-globe.scm b/plug-ins/script-fu/scripts/spinning-globe.scm
new file mode 100644
index 0000000..1549830
--- /dev/null
+++ b/plug-ins/script-fu/scripts/spinning-globe.scm
@@ -0,0 +1,110 @@
+;
+; anim_sphere
+;
+;
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+; Define the function:
+
+(define (script-fu-spinning-globe inImage
+ inLayer
+ inFrames
+ inFromLeft
+ inTransparent
+ inIndex
+ inCopy)
+ (let* (
+ (theImage (if (= inCopy TRUE)
+ (car (gimp-image-duplicate inImage))
+ inImage))
+ (theLayer (car (gimp-image-get-active-layer theImage)))
+ (n 0)
+ (ang (* (/ 360 inFrames)
+ (if (= inFromLeft TRUE) 1 -1) ))
+ (theFrame 0)
+ )
+
+ (gimp-layer-add-alpha theLayer)
+
+ (while (> inFrames n)
+ (set! n (+ n 1))
+ (set! theFrame (car (gimp-layer-copy theLayer FALSE)))
+ (gimp-image-insert-layer theImage theFrame 0 0)
+ (gimp-item-set-name theFrame
+ (string-append "Anim Frame: "
+ (number->string (- inFrames n) 10)
+ " (replace)"))
+ (plug-in-map-object RUN-NONINTERACTIVE
+ theImage theFrame ; mapping
+ 1 ; viewpoint
+ 0.5 0.5 2.0 ; object pos
+ 0.5 0.5 0.0 ; first axis
+ 1.0 0.0 0.0 ; 2nd axis
+ 0.0 1.0 0.0 ; axis rotation
+ 0.0 (* n ang) 0.0 ; light (type, color)
+ 0 '(255 255 255) ; light position
+ -0.5 -0.5 2.0 ; light direction
+ -1.0 -1.0 1.0 ; material (amb, diff, refl, spec, high)
+ 0.3 1.0 0.5 0.0 27.0 ; antialias
+ TRUE ; tile
+ FALSE ; new image
+ FALSE ; transparency
+ inTransparent ; radius
+ 0.25 ; unused parameters
+ 1.0 1.0 1.0 1.0
+ -1 -1 -1 -1 -1 -1 -1 -1
+ )
+ )
+
+ (gimp-image-remove-layer theImage theLayer)
+ (plug-in-autocrop RUN-NONINTERACTIVE theImage theFrame)
+
+ (if (= inIndex 0)
+ ()
+ (gimp-image-convert-indexed theImage CONVERT-DITHER-FS CONVERT-PALETTE-GENERATE inIndex
+ FALSE FALSE ""))
+
+ (if (= inCopy TRUE)
+ (begin
+ (gimp-image-clean-all theImage)
+ (gimp-display-new theImage)
+ )
+ )
+
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register
+ "script-fu-spinning-globe"
+ _"_Spinning Globe..."
+ _"Create an animation by mapping the current image onto a spinning sphere"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "16th April 1998"
+ "RGB* GRAY*"
+ SF-IMAGE "The Image" 0
+ SF-DRAWABLE "The Layer" 0
+ SF-ADJUSTMENT _"Frames" '(10 1 360 1 10 0 1)
+ SF-TOGGLE _"Turn from left to right" FALSE
+ SF-TOGGLE _"Transparent background" TRUE
+ SF-ADJUSTMENT _"Index to n colors (0 = remain RGB)" '(63 0 256 1 10 0 1)
+ SF-TOGGLE _"Work on copy" TRUE
+)
+
+(script-fu-menu-register "script-fu-spinning-globe"
+ "<Image>/Filters/Animation/Animators")
diff --git a/plug-ins/script-fu/scripts/spyrogimp.scm b/plug-ins/script-fu/scripts/spyrogimp.scm
new file mode 100644
index 0000000..0a1e40c
--- /dev/null
+++ b/plug-ins/script-fu/scripts/spyrogimp.scm
@@ -0,0 +1,352 @@
+; spyrogimp.scm -*-scheme-*-
+; Draws Spirographs, Epitrochoids and Lissajous Curves.
+; More info at http://www.wisdom.weizmann.ac.il/~elad/spyrogimp/
+; Version 1.2
+;
+; Copyright (C) 2003 by Elad Shahar <elad@wisdom.weizmann.ac.il>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+; This routine is invoked by a dialog.
+; It is the main routine in this file.
+(define (script-fu-spyrogimp img drw
+ type shape
+ oteeth iteeth
+ margin hole-ratio start-angle
+ tool brush
+ color-method color grad)
+
+ ; Internal function to draw the spyro.
+ (define (script-fu-spyrogimp-internal img drw
+ x1 y1 x2 y2 ; Bounding box.
+ type ; = 0 (Spirograph), 1 (Epitrochoid), 2(Lissajous) .
+ shape ; = 0 (Circle), 1 (Frame), >2 (Polygons) .
+ oteeth iteeth ; Outer and inner teeth.
+ margin hole-ratio
+ start-angle ; 0 <= start-angle < 360 .
+ tool ; = 0 (Pencil), 1 (Brush), 2 (Airbrush) .
+ brush
+ color-method ; = 0 (Single color), 1 (Grad. Loop Sawtooth),
+ ; 2 (Grad. Loop triangle) .
+ color ; Used when color-method = Single color .
+ grad ; Gradient used in Gradient color methods.
+ )
+
+
+ ; This function returns a list of samples according to the gradient.
+ (define (get-gradient steps color-method grad)
+ (if (= color-method 1)
+ ; option 1
+ ; Just return the gradient
+ (gimp-gradient-get-uniform-samples grad (min steps 50) FALSE)
+
+ ; option 2
+ ; The returned list is such that the gradient appears two times, once
+ ; in the normal order and once in reverse. This way there are no color
+ ; jumps if we go beyond the edge
+ (let* (
+ ; Sample the gradient into array "gr".
+ (gr (gimp-gradient-get-uniform-samples grad
+ (/ (min steps 50) 2)
+ FALSE))
+
+ (grn (car gr)) ; length of sample array.
+ (gra (cadr gr)) ; array of color samples (R1,G1,B1,A1, R2,....)
+
+ ; Allocate array gra-new of size (2 * grn) - 8,
+ ; but since each 4 items is actually one (RGBA) tuple,
+ ; it contains 2x - 2 entries.
+ (grn-new (+ grn grn -8))
+ (gra-new (cons-array grn-new 'double))
+
+ (gr-index 0)
+ (gr-index2 0)
+ )
+
+ ; Copy original array gra to gra_new.
+ (while (< gr-index grn)
+ (aset gra-new gr-index (aref gra gr-index))
+ (set! gr-index (+ 1 gr-index))
+ )
+
+ ; Copy second time, but in reverse
+ (set! gr-index2 (- gr-index 8))
+ (while (< gr-index grn-new)
+ (aset gra-new gr-index (aref gra gr-index2))
+ (set! gr-index (+ 1 gr-index))
+ (set! gr-index2 (+ 1 gr-index2))
+
+ (if (= (fmod gr-index 4) 0)
+ (set! gr-index2 (- gr-index2 8))
+ )
+ )
+
+ ; Return list.
+ (list grn-new gra-new)
+ )
+ )
+ )
+
+
+ (let* (
+ (steps (+ 1 (lcm oteeth iteeth)))
+ (*points* (cons-array (* steps 2) 'double))
+
+ (ot 0) ; current outer tooth
+ (cx 0) ; Current x,y
+ (cy 0)
+
+ ; If its a polygon or frame, how many sides does it have.
+ (poly (if (= shape 1) 4 ; A frame has four sides.
+ (if (> shape 1) (+ shape 1) 0)))
+
+ (2pi (* 2 *pi*))
+
+ (drw-width (- x2 x1))
+ (drw-height (- y2 y1))
+ (half-width (/ drw-width 2))
+ (half-height (/ drw-height 2))
+ (midx (+ x1 half-width))
+ (midy (+ y1 half-height))
+
+ (hole (* hole-ratio
+ (- (/ (min drw-width drw-height) 2) margin)
+ )
+ )
+ (irad (+ hole margin))
+
+ (radx (- half-width irad)) ;
+ (rady (- half-height irad)) ;
+
+ (gradt (get-gradient steps color-method grad))
+ (grada (cadr gradt)) ; Gradient array.
+ (gradn (car gradt)) ; Number of entries of gradients.
+
+ ; Indexes
+ (grad-index 0) ; for array: grada
+ (point-index 0) ; for array: *points*
+ (index 0)
+ )
+
+ ; Do one step of the loop.
+ (define (calc-and-step!)
+ (let* (
+ (oangle (* 2pi (/ ot oteeth)) )
+ (shifted-oangle (+ oangle (* 2pi (/ start-angle 360))) )
+ (xfactor (cos shifted-oangle))
+ (yfactor (sin shifted-oangle))
+ (lenfactor 1)
+ (ofactor (/ (+ oteeth iteeth) iteeth))
+
+ ; The direction of the factor changes according
+ ; to whether the type is a sypro or an epitcorhoid.
+ (mfactor (if (= type 0) (- ofactor) ofactor))
+ )
+
+ ; If we are drawing a polygon then compute a contortion
+ ; factor "lenfactor" which deforms the standard circle.
+ (if (> poly 2)
+ (let* (
+ (pi4 (/ *pi* poly))
+ (pi2 (* pi4 2))
+
+ (oanglemodpi2 (fmod (+ oangle
+ (if (= 1 (fmod poly 2))
+ 0 ;(/ pi4 2)
+ 0
+ )
+ )
+ pi2))
+ )
+
+ (set! lenfactor (/ ( if (= shape 1) 1 (cos pi4) )
+ (cos
+ (if (< oanglemodpi2 pi4)
+ oanglemodpi2
+ (- pi2 oanglemodpi2)
+ )
+ )
+ )
+ )
+ )
+ )
+
+ (if (= type 2)
+ (begin ; Lissajous
+ (set! cx (+ midx
+ (* half-width (cos shifted-oangle)) ))
+ (set! cy (+ midy
+ (* half-height (cos (* mfactor oangle))) ))
+ )
+ (begin ; Spyrograph or Epitrochoid
+ (set! cx (+ midx
+ (* radx xfactor lenfactor)
+ (* hole (cos (* mfactor oangle) ) ) ))
+ (set! cy (+ midy
+ (* rady yfactor lenfactor)
+ (* hole (sin (* mfactor oangle) ) ) ))
+ )
+ )
+
+ ;; Advance teeth
+ (set! ot (+ ot 1))
+ )
+ )
+
+
+ ;; Draw all the points in *points* with appropriate tool.
+ (define (flush-points len)
+ (if (= tool 0)
+ (gimp-pencil drw len *points*) ; Use pencil
+ (if (= tool 1)
+ (gimp-paintbrush-default drw len *points*); use paintbrush
+ (gimp-airbrush-default drw len *points*) ; use airbrush
+ )
+ )
+
+ ; Reset points array, but copy last point to first
+ ; position so it will connect the next time.
+ (aset *points* 0 (aref *points* (- point-index 2)))
+ (aset *points* 1 (aref *points* (- point-index 1)))
+ (set! point-index 2)
+ )
+
+ ;;
+ ;; Execution starts here.
+ ;;
+
+ (gimp-context-push)
+
+ (gimp-image-undo-group-start img)
+
+ ; Set new color, brush, opacity, paint mode.
+ (gimp-context-set-foreground color)
+ (gimp-context-set-brush (car brush))
+ (gimp-context-set-opacity (car (cdr brush)))
+ (gimp-context-set-paint-mode (car (cdr (cdr (cdr brush)))))
+
+ (gimp-progress-set-text _"Rendering Spyro")
+
+ (while (< index steps)
+
+ (calc-and-step!)
+
+ (aset *points* point-index cx)
+ (aset *points* (+ point-index 1) cy)
+ (set! point-index (+ point-index 2))
+
+ ; Change color and draw points if using gradient.
+ (if (< 0 color-method) ; use gradient.
+ (if (< (/ (+ grad-index 4) gradn) (/ index steps))
+ (begin
+ (gimp-context-set-foreground
+ (list
+ (* 255 (aref grada grad-index))
+ (* 255 (aref grada (+ 1 grad-index)) )
+ (* 255 (aref grada (+ 2 grad-index)) )
+ )
+ )
+ (gimp-context-set-opacity (* 100 (aref grada (+ 3 grad-index) ) ) )
+ (set! grad-index (+ 4 grad-index))
+
+ ; Draw points
+ (flush-points point-index)
+ )
+ )
+ )
+
+ (set! index (+ index 1))
+
+ (if (= 0 (modulo index 16))
+ (gimp-progress-update (/ index steps))
+ )
+ )
+
+ ; Draw remaining points.
+ (flush-points point-index)
+
+ (gimp-progress-update 1.0)
+
+ (gimp-image-undo-group-end img)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+ )
+
+ (let* (
+ ; Get current selection to determine where to draw.
+ (bounds (cdr (gimp-selection-bounds img)))
+ (x1 (car bounds))
+ (y1 (cadr bounds))
+ (x2 (caddr bounds))
+ (y2 (car (cdddr bounds)))
+ )
+
+ (set! oteeth (trunc (+ oteeth 0.5)))
+ (set! iteeth (trunc (+ iteeth 0.5)))
+
+ (script-fu-spyrogimp-internal img drw
+ x1 y1 x2 y2
+ type shape
+ oteeth iteeth
+ margin hole-ratio start-angle
+ tool brush
+ color-method color grad)
+ )
+)
+
+
+
+(script-fu-register "script-fu-spyrogimp"
+ _"_Spyrogimp (older script-fu version)..."
+ _"This procedure is deprecated! Use 'plug-in-spyrogimp' instead."
+ "Elad Shahar <elad@wisdom.weizmann.ac.il>"
+ "Elad Shahar"
+ "June 2003"
+ "RGB*, INDEXED*, GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+
+ SF-OPTION _"Type" '(_"Spyrograph"
+ _"Epitrochoid"
+ _"Lissajous")
+ SF-OPTION _"Shape" '(_"Circle"
+ _"Frame"
+ _"Triangle"
+ _"Square"
+ _"Pentagon"
+ _"Hexagon"
+ _"Polygon: 7 sides"
+ _"Polygon: 8 sides"
+ _"Polygon: 9 sides"
+ _"Polygon: 10 sides")
+ SF-ADJUSTMENT _"Outer teeth" '(86 1 120 1 10 0 0)
+ SF-ADJUSTMENT _"Inner teeth" '(70 1 120 1 10 0 0)
+ SF-ADJUSTMENT _"Margin (pixels)" '(0 -10000 10000 1 10 0 1)
+ SF-ADJUSTMENT _"Hole ratio" '(0.4 0.0 1.0 0.01 0.1 2 0)
+ SF-ADJUSTMENT _"Start angle" '(0 0 359 1 10 0 0)
+
+ SF-OPTION _"Tool" '(_"Pencil"
+ _"Brush"
+ _"Airbrush")
+ SF-BRUSH _"Brush" '("Circle (01)" 100 -1 0)
+
+ SF-OPTION _"Color method" '(_"Solid Color"
+ _"Gradient: Loop Sawtooth"
+ _"Gradient: Loop Triangle")
+ SF-COLOR _"Color" "black"
+ SF-GRADIENT _"Gradient" "Deep Sea"
+)
diff --git a/plug-ins/script-fu/scripts/test-sphere.scm b/plug-ins/script-fu/scripts/test-sphere.scm
new file mode 100644
index 0000000..763e9b0
--- /dev/null
+++ b/plug-ins/script-fu/scripts/test-sphere.scm
@@ -0,0 +1,307 @@
+; This is a a test script to show and test the possibilities of the
+; Script-Fu parameter API.
+;
+; ----------------------------------------------------------------------
+; SF-ADJUSTMENT
+; is only useful in interactive mode, if you call a script from
+; the console, it acts just like a normal SF-VALUE
+; In interactive mode it creates an adjustment widget in the dialog.
+;
+; Usage:
+; SF-ADJUSTMENT "label" '(value lower upper step_inc page_inc digits type)
+;
+; type is one of: SF-SLIDER(0), SF-SPINNER(1)
+;
+; ----------------------------------------------------------------------
+; SF-COLOR
+; creates a color button in the dialog. It accepts either a list of three
+; values for the red, green and blue components or a color name in CSS
+; notatation
+;
+; Usage:
+; SF-COLOR "label" '(red green blue)
+; SF-COLOR "label" "color"
+;
+; ----------------------------------------------------------------------
+; SF-FONT
+; creates a font-selection widget in the dialog. It returns a fontname as
+; a string. There are two new gimp-text procedures to ease the use of this
+; return parameter:
+;
+; (gimp-text-fontname image drawable
+; x-pos y-pos text border antialias size unit font)
+; (gimp-text-get-extents-fontname text size unit font))
+;
+; where font is the fontname you get. The size specified in the fontname
+; is silently ignored. It is only used in the font-selector. So you are
+; asked to set it to a useful value (24 pixels is a good choice) when
+; using SF-FONT.
+;
+; Usage:
+; SF-FONT "label" "fontname"
+;
+; ----------------------------------------------------------------------
+; SF-BRUSH
+; is only useful in interactive mode. It will create a widget in the control
+; dialog. The widget consists of a preview area (which when pressed will
+; produce a popup preview ) and a button with the "..." label. The button will
+; popup a dialog where brushes can be selected and each of the
+; characteristics of the brush can be modified.
+;
+; The actual value returned when the script is invoked is a list
+; consisting of Brush name, opacity, spacing and brush mode in the same
+; units as passed in as the default value.
+;
+; Usage:
+; SF-BRUSH "Brush" '("Circle (03)" 100 44 0)
+;
+; Here the brush dialog will be popped up with a default brush of Circle (03)
+; opacity 100 spacing 44 and paint mode of Normal (value 0).
+; If this selection was unchanged the value passed to the function as a
+; parameter would be '("Circle (03)" 100 44 0).
+;
+; ----------------------------------------------------------------------
+; SF-PATTERN
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget consists of a preview area (which when pressed will
+; produce a popup preview ) and a button with the "..." label. The button will
+; popup a dialog where patterns can be selected.
+;
+; Usage:
+; SF-PATTERN "Pattern" "Maple Leaves"
+;
+; The value returned when the script is invoked is a string containing the
+; pattern name. If the above selection was not altered the string would
+; contain "Maple Leaves"
+;
+; ----------------------------------------------------------------------
+; SF-GRADIENT
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget consists of a button containing a preview of the selected
+; gradient. If the button is pressed a gradient selection dialog will popup.
+;
+; Usage:
+; SF-GRADIENT "Gradient" "Deep Sea"
+;
+; The value returned when the script is invoked is a string containing the
+; gradient name. If the above selection was not altered the string would
+; contain "Deep Sea"
+;
+; ----------------------------------------------------------------------
+; SF-PALETTE
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget consists of a button containing a preview of the selected
+; palette. If the button is pressed a palette selection dialog will popup.
+;
+; Usage:
+; SF-PALETTE "Palette" "Named Colors"
+;
+; The value returned when the script is invoked is a string containing the
+; palette name. If the above selection was not altered the string would
+; contain "Named Colors"
+;
+; ----------------------------------------------------------------------
+; SF-FILENAME
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget consists of a button containing the name of a file.
+; If the button is pressed a file selection dialog will popup.
+;
+; Usage:
+; SF-FILENAME "Environment Map"
+; (string-append "" gimp-data-directory "/scripts/beavis.jpg")
+;
+; The value returned when the script is invoked is a string containing the
+; filename.
+;
+; ----------------------------------------------------------------------
+; SF-DIRNAME
+; Only useful in interactive mode. Very similar to SF-FILENAME, but the
+; created widget allows to choose a directory instead of a file.
+;
+; Usage:
+; SF-DIRNAME "Image Directory" "/var/tmp/images"
+;
+; The value returned when the script is invoked is a string containing the
+; dirname.
+;
+; ----------------------------------------------------------------------
+; SF-OPTION
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget is a combo-box showing the options that are passed
+; as a list. The first option is the default choice.
+;
+; Usage:
+; SF-OPTION "Orientation" '("Horizontal" "Vertical")
+;
+; The value returned when the script is invoked is the number of the
+; chosen option, where the option first is counted as 0.
+;
+; ----------------------------------------------------------------------
+; SF-ENUM
+; Only useful in interactive mode. It will create a widget in the control
+; dialog. The widget is a combo-box showing all enum values for the given
+; enum type. This has to be the name of a registered enum, without the
+; "Gimp" prefix. The second parameter specifies the default value, using
+; the enum value's nick.
+;
+; Usage:
+; SF-ENUM "Interpolation" '("InterpolationType" "linear")
+;
+; The value returned when the script is invoked corresponds to chosen
+; enum value.
+;
+; ----------------------------------------------------------------------
+
+
+(define (script-fu-test-sphere radius
+ light
+ shadow
+ bg-color
+ sphere-color
+ brush
+ text
+ multi-text
+ pattern
+ gradient
+ gradient-reverse
+ font
+ size
+ unused-palette
+ unused-filename
+ unused-orientation
+ unused-interpolation
+ unused-dirname
+ unused-image
+ unused-layer
+ unused-channel
+ unused-drawable)
+ (let* (
+ (width (* radius 3.75))
+ (height (* radius 2.5))
+ (img (car (gimp-image-new width height RGB)))
+ (drawable (car (gimp-layer-new img width height RGB-IMAGE
+ "Sphere Layer" 100 LAYER-MODE-NORMAL)))
+ (radians (/ (* light *pi*) 180))
+ (cx (/ width 2))
+ (cy (/ height 2))
+ (light-x (+ cx (* radius (* 0.6 (cos radians)))))
+ (light-y (- cy (* radius (* 0.6 (sin radians)))))
+ (light-end-x (+ cx (* radius (cos (+ *pi* radians)))))
+ (light-end-y (- cy (* radius (sin (+ *pi* radians)))))
+ (offset (* radius 0.1))
+ (text-extents (gimp-text-get-extents-fontname multi-text
+ size PIXELS
+ font))
+ (x-position (- cx (/ (car text-extents) 2)))
+ (y-position (- cy (/ (cadr text-extents) 2)))
+ (shadow-w 0)
+ (shadow-x 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+ (gimp-context-set-foreground sphere-color)
+ (gimp-context-set-background bg-color)
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+ (gimp-context-set-background '(20 20 20))
+
+ (if (and
+ (or (and (>= light 45) (<= light 75))
+ (and (<= light 135) (>= light 105)))
+ (= shadow TRUE))
+ (let ((shadow-w (* (* radius 2.5) (cos (+ *pi* radians))))
+ (shadow-h (* radius 0.5))
+ (shadow-x cx)
+ (shadow-y (+ cy (* radius 0.65))))
+ (if (< shadow-w 0)
+ (begin (set! shadow-x (+ cx shadow-w))
+ (set! shadow-w (- shadow-w))))
+
+ (gimp-context-set-feather TRUE)
+ (gimp-context-set-feather-radius 7.5 7.5)
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE shadow-x shadow-y shadow-w shadow-h)
+ (gimp-context-set-pattern pattern)
+ (gimp-drawable-edit-fill drawable FILL-PATTERN)))
+
+ (gimp-context-set-feather FALSE)
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE (- cx radius) (- cy radius)
+ (* 2 radius) (* 2 radius))
+
+ (gimp-context-set-gradient-fg-bg-rgb)
+ (gimp-drawable-edit-gradient-fill drawable
+ GRADIENT-RADIAL offset
+ FALSE 0 0
+ TRUE
+ light-x light-y
+ light-end-x light-end-y)
+
+ (gimp-selection-none img)
+
+ (gimp-image-select-ellipse img CHANNEL-OP-REPLACE 10 10 50 50)
+
+ (gimp-context-set-gradient gradient)
+ (gimp-context-set-gradient-reverse gradient-reverse)
+ (gimp-drawable-edit-gradient-fill drawable
+ GRADIENT-LINEAR offset
+ FALSE 0 0
+ TRUE
+ 10 10
+ 30 60)
+
+ (gimp-selection-none img)
+
+ (gimp-context-set-foreground '(0 0 0))
+ (gimp-floating-sel-anchor (car (gimp-text-fontname img drawable
+ x-position y-position
+ multi-text
+ 0 TRUE
+ size PIXELS
+ font)))
+
+ (gimp-image-undo-enable img)
+ (gimp-display-new img)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-test-sphere"
+ _"_Sphere..."
+ "Simple script to test and show the usage of the new Script-Fu API extensions."
+ "Spencer Kimball, Sven Neumann"
+ "Spencer Kimball"
+ "1996, 1998"
+ ""
+ SF-ADJUSTMENT "Radius (in pixels)" (list 100 1 5000 1 10 0 SF-SPINNER)
+ SF-ADJUSTMENT "Lighting (degrees)" (list 45 0 360 1 10 1 SF-SLIDER)
+ SF-TOGGLE "Shadow" TRUE
+ SF-COLOR "Background color" "white"
+ SF-COLOR "Sphere color" "red"
+ SF-BRUSH "Brush" '("2. Hardness 100" 100 44 0)
+ SF-STRING "Text" "Tiny-Fu rocks!"
+ SF-TEXT "Multi-line text" "Hello,\nWorld!"
+ SF-PATTERN "Pattern" "Maple Leaves"
+ SF-GRADIENT "Gradient" "Deep Sea"
+ SF-TOGGLE "Gradient reverse" FALSE
+ SF-FONT "Font" "Agate"
+ SF-ADJUSTMENT "Font size (pixels)" '(50 1 1000 1 10 0 1)
+ SF-PALETTE "Palette" "Default"
+ SF-FILENAME "Environment map"
+ (string-append gimp-data-directory
+ "/scripts/images/beavis.jpg")
+ SF-OPTION "Orientation" '("Horizontal"
+ "Vertical")
+ SF-ENUM "Interpolation" '("InterpolationType" "linear")
+ SF-DIRNAME "Output directory" "/var/tmp/"
+ SF-IMAGE "Image" -1
+ SF-LAYER "Layer" -1
+ SF-CHANNEL "Channel" -1
+ SF-DRAWABLE "Drawable" -1
+ SF-VECTORS "Vectors" -1
+)
+
+(script-fu-menu-register "script-fu-test-sphere"
+ "<Image>/Filters/Languages/Script-Fu/Test")
diff --git a/plug-ins/script-fu/scripts/tileblur.scm b/plug-ins/script-fu/scripts/tileblur.scm
new file mode 100644
index 0000000..4be7a6c
--- /dev/null
+++ b/plug-ins/script-fu/scripts/tileblur.scm
@@ -0,0 +1,83 @@
+; Chris Gutteridge (cjg@ecs.soton.ac.uk)
+; At ECS Dept, University of Southampton, England.
+
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-tile-blur inImage inLayer inRadius inVert inHoriz inType)
+
+ (let* (
+ (theImage inImage)
+ (theLayer inLayer)
+ (theHeight (car (gimp-drawable-height theLayer)))
+ (theWidth (car (gimp-drawable-width theLayer)))
+ )
+
+ (define (pasteat xoff yoff)
+ (let ((theFloat (car(gimp-edit-paste theLayer 0))))
+ (gimp-layer-set-offsets theFloat (* xoff theWidth) (* yoff theHeight) )
+ (gimp-floating-sel-anchor theFloat)
+ )
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-feather FALSE)
+ (gimp-image-undo-group-start theImage)
+
+ (gimp-layer-resize theLayer (* 3 theWidth) (* 3 theHeight) 0 0)
+
+ (gimp-image-select-rectangle theImage CHANNEL-OP-REPLACE 0 0 theWidth theHeight)
+ (gimp-edit-cut theLayer)
+
+ (gimp-selection-none theImage)
+ (gimp-layer-set-offsets theLayer theWidth theHeight)
+
+ (pasteat 1 1) (pasteat 1 2) (pasteat 1 3)
+ (pasteat 2 1) (pasteat 2 2) (pasteat 2 3)
+ (pasteat 3 1) (pasteat 3 2) (pasteat 3 3)
+
+ (gimp-selection-none theImage)
+ (if (= inType 0)
+ (plug-in-gauss-iir RUN-NONINTERACTIVE
+ theImage theLayer inRadius inHoriz inVert)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE
+ theImage theLayer inRadius inHoriz inVert)
+ )
+
+ (gimp-layer-resize theLayer
+ theWidth theHeight (- 0 theWidth) (- 0 theHeight))
+ (gimp-layer-set-offsets theLayer 0 0)
+ (gimp-image-undo-group-end theImage)
+ (gimp-displays-flush)
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-tile-blur"
+ _"_Tileable Blur..."
+ _"Blur the edges of an image so the result tiles seamlessly"
+ "Chris Gutteridge"
+ "1998, Chris Gutteridge / ECS dept, University of Southampton, England."
+ "25th April 1998"
+ "RGB*"
+ SF-IMAGE "The Image" 0
+ SF-DRAWABLE "The Layer" 0
+ SF-ADJUSTMENT _"Radius" '(5 0 128 1 1 0 0)
+ SF-TOGGLE _"Blur vertically" TRUE
+ SF-TOGGLE _"Blur horizontally" TRUE
+ SF-OPTION _"Blur type" '(_"IIR" _"RLE")
+)
+
+(script-fu-menu-register "script-fu-tile-blur"
+ "<Image>/Filters/Blur")
diff --git a/plug-ins/script-fu/scripts/ts-helloworld.scm b/plug-ins/script-fu/scripts/ts-helloworld.scm
new file mode 100644
index 0000000..2c04105
--- /dev/null
+++ b/plug-ins/script-fu/scripts/ts-helloworld.scm
@@ -0,0 +1,65 @@
+; "Hello, World" Test v1.00 February 29, 2004
+; by Kevin Cozens <kcozens@interlog.com>
+;
+; Creates an image with the text "Hello, World!"
+; This was the first TinyScheme based script ever created and run for the
+; 2.x version of GIMP.
+
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+; Tiny-Fu first successfully ran this script at 2:07am on March 6, 2004.
+
+(define (script-fu-helloworld text font size color)
+ (let* (
+ (width 10)
+ (height 10)
+ (img (car (gimp-image-new width height RGB)))
+ (text-layer)
+ )
+
+ (gimp-context-push)
+
+ (gimp-image-undo-disable img)
+ (gimp-context-set-foreground color)
+
+ (set! text-layer (car (gimp-text-fontname img -1 0 0 text 10 TRUE size PIXELS font)))
+ (set! width (car (gimp-drawable-width text-layer)))
+ (set! height (car (gimp-drawable-height text-layer)))
+ (gimp-image-resize img width height 0 0)
+
+ (gimp-image-undo-enable img)
+ (gimp-display-new img)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-helloworld"
+ "_Hello World..."
+ "Creates an image with a user specified text string."
+ "Kevin Cozens <kcozens@interlog.com>"
+ "Kevin Cozens"
+ "February 29, 2004"
+ ""
+ SF-STRING "Text string" "Hello, World!"
+ SF-FONT "Font" "Sans"
+ SF-ADJUSTMENT "Font size (pixels)" '(100 2 1000 1 10 0 1)
+ SF-COLOR "Color" '(0 0 0)
+)
+
+(script-fu-menu-register "script-fu-helloworld"
+ "<Image>/Filters/Languages/Script-Fu/Test")
diff --git a/plug-ins/script-fu/scripts/unsharp-mask.scm b/plug-ins/script-fu/scripts/unsharp-mask.scm
new file mode 100644
index 0000000..77daf82
--- /dev/null
+++ b/plug-ins/script-fu/scripts/unsharp-mask.scm
@@ -0,0 +1,84 @@
+;;; unsharp-mask.scm
+;;; Time-stamp: <1998/11/17 13:18:39 narazaki@gimp.org>
+;;; Author: Narazaki Shuji <narazaki@gimp.org>
+;;; Version 0.8
+
+(define (script-fu-unsharp-mask img drw mask-size mask-opacity)
+ (let* (
+ (drawable-width (car (gimp-drawable-width drw)))
+ (drawable-height (car (gimp-drawable-height drw)))
+ (new-image (car (gimp-image-new drawable-width drawable-height RGB)))
+ (original-layer (car (gimp-layer-new new-image
+ drawable-width drawable-height
+ RGB-IMAGE "Original"
+ 100 LAYER-MODE-NORMAL)))
+ (original-layer-for-darker 0)
+ (original-layer-for-lighter 0)
+ (blurred-layer-for-darker 0)
+ (blurred-layer-for-lighter 0)
+ (darker-layer 0)
+ (lighter-layer 0)
+ )
+
+ (gimp-selection-all img)
+ (gimp-edit-copy drw)
+
+ (gimp-image-undo-disable new-image)
+
+ (gimp-image-insert-layer new-image original-layer 0 0)
+ (gimp-floating-sel-anchor
+ (car (gimp-edit-paste original-layer FALSE)))
+
+ (set! original-layer-for-darker (car (gimp-layer-copy original-layer TRUE)))
+ (set! original-layer-for-lighter (car (gimp-layer-copy original-layer TRUE)))
+ (set! blurred-layer-for-darker (car (gimp-layer-copy original-layer TRUE)))
+ (gimp-item-set-visible original-layer FALSE)
+ (gimp-display-new new-image)
+
+ ;; make darker mask
+ (gimp-image-insert-layer new-image blurred-layer-for-darker 0 -1)
+ (plug-in-gauss-iir RUN-NONINTERACTIVE
+ new-image blurred-layer-for-darker mask-size TRUE TRUE)
+ (set! blurred-layer-for-lighter
+ (car (gimp-layer-copy blurred-layer-for-darker TRUE)))
+ (gimp-image-insert-layer new-image original-layer-for-darker 0 -1)
+ (gimp-layer-set-mode original-layer-for-darker LAYER-MODE-SUBTRACT)
+ (set! darker-layer
+ (car (gimp-image-merge-visible-layers new-image CLIP-TO-IMAGE)))
+ (gimp-item-set-name darker-layer "darker mask")
+ (gimp-item-set-visible darker-layer FALSE)
+
+ ;; make lighter mask
+ (gimp-image-insert-layer new-image original-layer-for-lighter 0 -1)
+ (gimp-image-insert-layer new-image blurred-layer-for-lighter 0 -1)
+ (gimp-layer-set-mode blurred-layer-for-lighter LAYER-MODE-SUBTRACT)
+ (set! lighter-layer
+ (car (gimp-image-merge-visible-layers new-image CLIP-TO-IMAGE)))
+ (gimp-item-set-name lighter-layer "lighter mask")
+
+ ;; combine them
+ (gimp-item-set-visible original-layer TRUE)
+ (gimp-layer-set-mode darker-layer LAYER-MODE-SUBTRACT)
+ (gimp-layer-set-opacity darker-layer mask-opacity)
+ (gimp-item-set-visible darker-layer TRUE)
+ (gimp-layer-set-mode lighter-layer LAYER-MODE-ADDITION)
+ (gimp-layer-set-opacity lighter-layer mask-opacity)
+ (gimp-item-set-visible lighter-layer TRUE)
+
+ (gimp-image-undo-enable new-image)
+ (gimp-displays-flush)
+ )
+)
+
+(script-fu-register "script-fu-unsharp-mask"
+ "Unsharp Mask..."
+ "Make a new image from the current layer by applying the unsharp mask method"
+ "Shuji Narazaki <narazaki@gimp.org>"
+ "Shuji Narazaki"
+ "1997,1998"
+ ""
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable to apply" 0
+ SF-ADJUSTMENT _"Mask size" '(5 1 100 1 1 0 1)
+ SF-ADJUSTMENT _"Mask opacity" '(50 0 100 1 1 0 1)
+)
diff --git a/plug-ins/script-fu/scripts/waves-anim.scm b/plug-ins/script-fu/scripts/waves-anim.scm
new file mode 100644
index 0000000..4e43d98
--- /dev/null
+++ b/plug-ins/script-fu/scripts/waves-anim.scm
@@ -0,0 +1,110 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+;
+;
+; waves-anim.scm version 1.01 1997/12/13
+;
+; CHANGE-LOG:
+; 1.00 - initial release
+; 1.01 - some code cleanup, no real changes
+;
+; Copyright (C) 1997 Sven Neumann <sven@gimp.org>
+;
+;
+; Makes a copy of your image and creates an animation of the active layer
+; as if a stone was thrown into the image. The animation may be saved with
+; the gif-plug-in.
+
+(define (script-fu-waves-anim img
+ drawable
+ amplitude
+ wavelength
+ num-frames
+ invert)
+ (let* ((amplitude (max 0 amplitude))
+ (wavelength (max 0 wavelength))
+ (num-frames (max 1 num-frames))
+ (remaining-frames num-frames)
+ (phase 0)
+ (phaseshift (/ 360 num-frames))
+ (image (car (gimp-image-duplicate img)))
+ (source-layer (car (gimp-image-get-active-layer image))))
+
+ (gimp-image-undo-disable image)
+
+ (if (= invert TRUE)
+ (set! phaseshift (- 0 phaseshift)))
+
+ (while (> remaining-frames 1)
+ (let* (
+ (waves-layer (car (gimp-layer-copy source-layer TRUE)))
+ (layer-name (string-append "Frame "
+ (number->string
+ (- (+ num-frames 2)
+ remaining-frames) 10
+ )
+ " (replace)"))
+ )
+ (gimp-layer-set-lock-alpha waves-layer FALSE)
+ (gimp-image-insert-layer image waves-layer 0 -1)
+ (gimp-item-set-name waves-layer layer-name)
+
+ (plug-in-waves RUN-NONINTERACTIVE
+ image
+ waves-layer
+ amplitude
+ phase
+ wavelength
+ 0
+ FALSE)
+
+ (set! remaining-frames (- remaining-frames 1))
+ (set! phase (- phase phaseshift))
+ )
+ )
+
+ (gimp-item-set-name source-layer "Frame 1")
+ (plug-in-waves RUN-NONINTERACTIVE
+ image
+ source-layer
+ amplitude
+ phase
+ wavelength
+ 0
+ FALSE)
+
+ (gimp-image-undo-enable image)
+ (gimp-display-new image)
+ )
+)
+
+(script-fu-register "script-fu-waves-anim"
+ _"_Waves..."
+ _"Create a multi-layer image with an effect like a stone was thrown into the current image"
+ "Sven Neumann <sven@gimp.org>"
+ "Sven Neumann"
+ "1997/13/12"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Amplitude" '(10 1 101 1 10 1 0)
+ SF-ADJUSTMENT _"Wavelength" '(10 0.1 100 1 10 1 0)
+ SF-ADJUSTMENT _"Number of frames" '(6 1 512 1 10 0 1)
+ SF-TOGGLE _"Invert direction" FALSE
+)
+
+(script-fu-menu-register "script-fu-waves-anim"
+ "<Image>/Filters/Animation/Animators")
diff --git a/plug-ins/script-fu/scripts/weave.scm b/plug-ins/script-fu/scripts/weave.scm
new file mode 100644
index 0000000..81fd0a7
--- /dev/null
+++ b/plug-ins/script-fu/scripts/weave.scm
@@ -0,0 +1,415 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; Weave script --- make an image look as if it were woven
+; Copyright (C) 1997 Federico Mena Quintero
+; federico@nuclecu.unam.mx
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+; Copies the specified rectangle from/to the specified drawable
+
+(define (copy-rectangle img
+ drawable
+ x1
+ y1
+ width
+ height
+ dest-x
+ dest-y)
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE x1 y1 width height)
+ (gimp-edit-copy drawable)
+ (let ((floating-sel (car (gimp-edit-paste drawable FALSE))))
+ (gimp-layer-set-offsets floating-sel dest-x dest-y)
+ (gimp-floating-sel-anchor floating-sel))
+ (gimp-selection-none img))
+
+; Creates a single weaving tile
+
+(define (create-weave-tile ribbon-width
+ ribbon-spacing
+ shadow-darkness
+ shadow-depth)
+ (let* ((tile-size (+ (* 2 ribbon-width) (* 2 ribbon-spacing)))
+ (darkness (* 255 (/ (- 100 shadow-darkness) 100)))
+ (img (car (gimp-image-new tile-size tile-size RGB)))
+ (drawable (car (gimp-layer-new img tile-size tile-size RGB-IMAGE
+ "Weave tile" 100 LAYER-MODE-NORMAL))))
+
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ ; Create main horizontal ribbon
+
+ (gimp-context-set-foreground '(255 255 255))
+ (gimp-context-set-background (list darkness darkness darkness))
+
+ (gimp-image-select-rectangle img
+ CHANNEL-OP-REPLACE
+ 0
+ ribbon-spacing
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ ribbon-width)
+
+ (gimp-context-set-gradient-fg-bg-rgb)
+ (gimp-drawable-edit-gradient-fill drawable
+ GRADIENT-BILINEAR (- 100 shadow-depth)
+ FALSE 0 0
+ TRUE
+ (/ (+ (* 2 ribbon-spacing) ribbon-width -1) 2) 0
+ 0 0)
+
+ ; Create main vertical ribbon
+
+ (gimp-image-select-rectangle img
+ CHANNEL-OP-REPLACE
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ 0
+ ribbon-width
+ (+ (* 2 ribbon-spacing) ribbon-width))
+
+ (gimp-drawable-edit-gradient-fill drawable
+ GRADIENT-BILINEAR (- 100 shadow-depth)
+ FALSE 0 0
+ TRUE
+ 0 (/ (+ (* 2 ribbon-spacing) ribbon-width -1) 2)
+ 0 0)
+
+ ; Create the secondary horizontal ribbon
+
+ (copy-rectangle img
+ drawable
+ 0
+ ribbon-spacing
+ (+ ribbon-width ribbon-spacing)
+ ribbon-width
+ (+ ribbon-width ribbon-spacing)
+ (+ (* 2 ribbon-spacing) ribbon-width))
+
+ (copy-rectangle img
+ drawable
+ (+ ribbon-width ribbon-spacing)
+ ribbon-spacing
+ ribbon-spacing
+ ribbon-width
+ 0
+ (+ (* 2 ribbon-spacing) ribbon-width))
+
+ ; Create the secondary vertical ribbon
+
+ (copy-rectangle img
+ drawable
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ 0
+ ribbon-width
+ (+ ribbon-width ribbon-spacing)
+ ribbon-spacing
+ (+ ribbon-width ribbon-spacing))
+
+ (copy-rectangle img
+ drawable
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ (+ ribbon-width ribbon-spacing)
+ ribbon-width
+ ribbon-spacing
+ ribbon-spacing
+ 0)
+
+ ; Done
+
+ (gimp-image-undo-enable img)
+ (list img drawable)))
+
+; Creates a complete weaving mask
+
+(define (create-weave width
+ height
+ ribbon-width
+ ribbon-spacing
+ shadow-darkness
+ shadow-depth)
+ (let* ((tile (create-weave-tile ribbon-width ribbon-spacing shadow-darkness
+ shadow-depth))
+ (tile-img (car tile))
+ (tile-layer (cadr tile))
+ (weaving (plug-in-tile RUN-NONINTERACTIVE tile-img tile-layer width height TRUE)))
+ (gimp-image-delete tile-img)
+ weaving))
+
+; Creates a single tile for masking
+
+(define (create-mask-tile ribbon-width
+ ribbon-spacing
+ r1-x1
+ r1-y1
+ r1-width
+ r1-height
+ r2-x1
+ r2-y1
+ r2-width
+ r2-height
+ r3-x1
+ r3-y1
+ r3-width
+ r3-height)
+ (let* ((tile-size (+ (* 2 ribbon-width) (* 2 ribbon-spacing)))
+ (img (car (gimp-image-new tile-size tile-size RGB)))
+ (drawable (car (gimp-layer-new img tile-size tile-size RGB-IMAGE
+ "Mask" 100 LAYER-MODE-NORMAL))))
+ (gimp-image-undo-disable img)
+ (gimp-image-insert-layer img drawable 0 0)
+
+ (gimp-context-set-background '(0 0 0))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+
+ (gimp-image-select-rectangle img CHANNEL-OP-REPLACE r1-x1 r1-y1 r1-width r1-height)
+ (gimp-image-select-rectangle img CHANNEL-OP-ADD r2-x1 r2-y1 r2-width r2-height)
+ (gimp-image-select-rectangle img CHANNEL-OP-ADD r3-x1 r3-y1 r3-width r3-height)
+
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+ (gimp-selection-none img)
+
+ (gimp-image-undo-enable img)
+
+ (list img drawable)))
+
+; Creates a complete mask image
+
+(define (create-mask final-width
+ final-height
+ ribbon-width
+ ribbon-spacing
+ r1-x1
+ r1-y1
+ r1-width
+ r1-height
+ r2-x1
+ r2-y1
+ r2-width
+ r2-height
+ r3-x1
+ r3-y1
+ r3-width
+ r3-height)
+ (let* ((tile (create-mask-tile ribbon-width ribbon-spacing
+ r1-x1 r1-y1 r1-width r1-height
+ r2-x1 r2-y1 r2-width r2-height
+ r3-x1 r3-y1 r3-width r3-height))
+ (tile-img (car tile))
+ (tile-layer (cadr tile))
+ (mask (plug-in-tile RUN-NONINTERACTIVE tile-img tile-layer final-width final-height
+ TRUE)))
+ (gimp-image-delete tile-img)
+ mask))
+
+; Creates the mask for horizontal ribbons
+
+(define (create-horizontal-mask ribbon-width
+ ribbon-spacing
+ final-width
+ final-height)
+ (create-mask final-width
+ final-height
+ ribbon-width
+ ribbon-spacing
+ 0
+ ribbon-spacing
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ ribbon-width
+ 0
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ ribbon-spacing
+ ribbon-width
+ (+ ribbon-width ribbon-spacing)
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ (+ ribbon-width ribbon-spacing)
+ ribbon-width))
+
+; Creates the mask for vertical ribbons
+
+(define (create-vertical-mask ribbon-width
+ ribbon-spacing
+ final-width
+ final-height)
+ (create-mask final-width
+ final-height
+ ribbon-width
+ ribbon-spacing
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ 0
+ ribbon-width
+ (+ (* 2 ribbon-spacing) ribbon-width)
+ ribbon-spacing
+ 0
+ ribbon-width
+ ribbon-spacing
+ ribbon-spacing
+ (+ ribbon-width ribbon-spacing)
+ ribbon-width
+ (+ ribbon-width ribbon-spacing)))
+
+; Adds a threads layer at a certain orientation to the specified image
+
+(define (create-threads-layer img
+ width
+ height
+ length
+ density
+ orientation)
+ (let* ((drawable (car (gimp-layer-new img width height RGBA-IMAGE
+ "Threads" 100 LAYER-MODE-NORMAL)))
+ (dense (/ density 100.0)))
+ (gimp-image-insert-layer img drawable 0 -1)
+ (gimp-context-set-background '(255 255 255))
+ (gimp-drawable-edit-fill drawable FILL-BACKGROUND)
+ (plug-in-noisify RUN-NONINTERACTIVE img drawable FALSE dense dense dense dense)
+ (plug-in-c-astretch RUN-NONINTERACTIVE img drawable)
+ (cond ((eq? orientation 'horizontal)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img drawable length TRUE FALSE))
+ ((eq? orientation 'vertical)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE img drawable length FALSE TRUE)))
+ (plug-in-c-astretch RUN-NONINTERACTIVE img drawable)
+ drawable))
+
+(define (create-complete-weave width
+ height
+ ribbon-width
+ ribbon-spacing
+ shadow-darkness
+ shadow-depth
+ thread-length
+ thread-density
+ thread-intensity)
+ (let* ((weave (create-weave width height ribbon-width ribbon-spacing
+ shadow-darkness shadow-depth))
+ (w-img (car weave))
+ (w-layer (cadr weave))
+
+ (h-layer (create-threads-layer w-img width height thread-length
+ thread-density 'horizontal))
+ (h-mask (car (gimp-layer-create-mask h-layer ADD-MASK-WHITE)))
+
+ (v-layer (create-threads-layer w-img width height thread-length
+ thread-density 'vertical))
+ (v-mask (car (gimp-layer-create-mask v-layer ADD-MASK-WHITE)))
+
+ (hmask (create-horizontal-mask ribbon-width ribbon-spacing
+ width height))
+ (hm-img (car hmask))
+ (hm-layer (cadr hmask))
+
+ (vmask (create-vertical-mask ribbon-width ribbon-spacing width height))
+ (vm-img (car vmask))
+ (vm-layer (cadr vmask)))
+
+ (gimp-layer-add-mask h-layer h-mask)
+ (gimp-selection-all hm-img)
+ (gimp-edit-copy hm-layer)
+ (gimp-image-delete hm-img)
+ (gimp-floating-sel-anchor (car (gimp-edit-paste h-mask FALSE)))
+ (gimp-layer-set-opacity h-layer thread-intensity)
+ (gimp-layer-set-mode h-layer LAYER-MODE-MULTIPLY)
+
+ (gimp-layer-add-mask v-layer v-mask)
+ (gimp-selection-all vm-img)
+ (gimp-edit-copy vm-layer)
+ (gimp-image-delete vm-img)
+ (gimp-floating-sel-anchor (car (gimp-edit-paste v-mask FALSE)))
+ (gimp-layer-set-opacity v-layer thread-intensity)
+ (gimp-layer-set-mode v-layer LAYER-MODE-MULTIPLY)
+
+ ; Uncomment this if you want to keep the weaving mask image
+ ; (gimp-display-new (car (gimp-image-duplicate w-img)))
+
+ (list w-img
+ (car (gimp-image-flatten w-img)))))
+
+; The main weave function
+
+(define (script-fu-weave img
+ drawable
+ ribbon-width
+ ribbon-spacing
+ shadow-darkness
+ shadow-depth
+ thread-length
+ thread-density
+ thread-intensity)
+ (gimp-context-push)
+ (gimp-image-undo-group-start img)
+
+ (let* (
+ (d-img (car (gimp-item-get-image drawable)))
+ (d-width (car (gimp-drawable-width drawable)))
+ (d-height (car (gimp-drawable-height drawable)))
+ (d-offsets (gimp-drawable-offsets drawable))
+
+ (weaving (create-complete-weave d-width
+ d-height
+ ribbon-width
+ ribbon-spacing
+ shadow-darkness
+ shadow-depth
+ thread-length
+ thread-density
+ thread-intensity))
+ (w-img (car weaving))
+ (w-layer (cadr weaving))
+ )
+
+ (gimp-context-set-paint-mode LAYER-MODE-NORMAL)
+ (gimp-context-set-opacity 100.0)
+ (gimp-context-set-feather FALSE)
+
+ (gimp-selection-all w-img)
+ (gimp-edit-copy w-layer)
+ (gimp-image-delete w-img)
+ (let ((floating-sel (car (gimp-edit-paste drawable FALSE))))
+ (gimp-layer-set-offsets floating-sel
+ (car d-offsets)
+ (cadr d-offsets))
+ (gimp-layer-set-mode floating-sel LAYER-MODE-MULTIPLY)
+ (gimp-floating-sel-to-layer floating-sel)
+ )
+ )
+ (gimp-context-pop)
+ (gimp-image-undo-group-end img)
+ (gimp-displays-flush)
+)
+
+(script-fu-register "script-fu-weave"
+ _"_Weave..."
+ _"Create a new layer filled with a weave effect to be used as an overlay or bump map"
+ "Federico Mena Quintero"
+ "Federico Mena Quintero"
+ "June 1997"
+ "RGB* GRAY*"
+ SF-IMAGE "Image to Weave" 0
+ SF-DRAWABLE "Drawable to Weave" 0
+ SF-ADJUSTMENT _"Ribbon width" '(30 0 256 1 10 1 1)
+ SF-ADJUSTMENT _"Ribbon spacing" '(10 0 256 1 10 1 1)
+ SF-ADJUSTMENT _"Shadow darkness" '(75 0 100 1 10 1 1)
+ SF-ADJUSTMENT _"Shadow depth" '(75 0 100 1 10 1 1)
+ SF-ADJUSTMENT _"Thread length" '(200 0 256 1 10 1 1)
+ SF-ADJUSTMENT _"Thread density" '(50 0 100 1 10 1 1)
+ SF-ADJUSTMENT _"Thread intensity" '(100 0 100 1 10 1 1)
+)
+
+(script-fu-menu-register "script-fu-weave"
+ "<Image>/Filters/Artistic")
diff --git a/plug-ins/script-fu/scripts/xach-effect.scm b/plug-ins/script-fu/scripts/xach-effect.scm
new file mode 100644
index 0000000..ae83885
--- /dev/null
+++ b/plug-ins/script-fu/scripts/xach-effect.scm
@@ -0,0 +1,142 @@
+; GIMP - The GNU Image Manipulation Program
+; Copyright (C) 1995 Spencer Kimball and Peter Mattis
+;
+; xach effect script
+; Copyright (c) 1997 Adrian Likins
+; aklikins@eos.ncsu.edu
+;
+; based on a idea by Xach Beane <xach@mint.net>
+;
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+(define (script-fu-xach-effect image
+ drawable
+ hl-offset-x
+ hl-offset-y
+ hl-color
+ hl-opacity-comp
+ ds-color
+ ds-opacity
+ ds-blur
+ ds-offset-x
+ ds-offset-y
+ keep-selection)
+ (let* (
+ (ds-blur (max ds-blur 0))
+ (ds-opacity (min ds-opacity 100))
+ (ds-opacity (max ds-opacity 0))
+ (type (car (gimp-drawable-type-with-alpha drawable)))
+ (image-width (car (gimp-image-width image)))
+ (hl-opacity (list hl-opacity-comp hl-opacity-comp hl-opacity-comp))
+ (image-height (car (gimp-image-height image)))
+ (active-selection 0)
+ (from-selection 0)
+ (theLayer 0)
+ (hl-layer 0)
+ (shadow-layer 0)
+ (mask 0)
+ )
+
+ (gimp-context-push)
+ (gimp-context-set-defaults)
+
+ (gimp-image-undo-group-start image)
+ (gimp-layer-add-alpha drawable)
+
+ (if (= (car (gimp-selection-is-empty image)) TRUE)
+ (begin
+ (gimp-image-select-item image CHANNEL-OP-REPLACE drawable)
+ (set! active-selection (car (gimp-selection-save image)))
+ (set! from-selection FALSE))
+ (begin
+ (set! from-selection TRUE)
+ (set! active-selection (car (gimp-selection-save image)))))
+
+ (set! hl-layer (car (gimp-layer-new image image-width image-height type _"Highlight" 100 LAYER-MODE-NORMAL)))
+ (gimp-image-insert-layer image hl-layer 0 -1)
+
+ (gimp-selection-none image)
+ (gimp-drawable-edit-clear hl-layer)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+
+ (gimp-context-set-background hl-color)
+ (gimp-drawable-edit-fill hl-layer FILL-BACKGROUND)
+ (gimp-selection-translate image hl-offset-x hl-offset-y)
+ (gimp-drawable-edit-fill hl-layer FILL-BACKGROUND)
+ (gimp-selection-none image)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+
+ (set! mask (car (gimp-layer-create-mask hl-layer ADD-MASK-WHITE)))
+ (gimp-layer-add-mask hl-layer mask)
+
+ (gimp-context-set-background hl-opacity)
+ (gimp-drawable-edit-fill mask FILL-BACKGROUND)
+
+ (set! shadow-layer (car (gimp-layer-new image
+ image-width
+ image-height
+ type
+ _"Shadow"
+ ds-opacity
+ LAYER-MODE-NORMAL)))
+ (gimp-image-insert-layer image shadow-layer 0 -1)
+ (gimp-selection-none image)
+ (gimp-drawable-edit-clear shadow-layer)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-selection-translate image ds-offset-x ds-offset-y)
+ (gimp-context-set-background ds-color)
+ (gimp-drawable-edit-fill shadow-layer FILL-BACKGROUND)
+ (gimp-selection-none image)
+ (plug-in-gauss-rle RUN-NONINTERACTIVE image shadow-layer ds-blur TRUE TRUE)
+ (gimp-image-select-item image CHANNEL-OP-REPLACE active-selection)
+ (gimp-drawable-edit-clear shadow-layer)
+ (gimp-image-lower-item image shadow-layer)
+
+ (if (= keep-selection FALSE)
+ (gimp-selection-none image))
+
+ (gimp-image-set-active-layer image drawable)
+ (gimp-image-remove-channel image active-selection)
+ (gimp-image-undo-group-end image)
+ (gimp-displays-flush)
+
+ (gimp-context-pop)
+ )
+)
+
+(script-fu-register "script-fu-xach-effect"
+ _"_Xach-Effect..."
+ _"Add a subtle translucent 3D effect to the selected region (or alpha)"
+ "Adrian Likins <adrian@gimp.org>"
+ "Adrian Likins"
+ "9/28/97"
+ "RGB* GRAY*"
+ SF-IMAGE "Image" 0
+ SF-DRAWABLE "Drawable" 0
+ SF-ADJUSTMENT _"Highlight X offset" '(-1 -100 100 1 10 0 1)
+ SF-ADJUSTMENT _"Highlight Y offset" '(-1 -100 100 1 10 0 1)
+ SF-COLOR _"Highlight color" "white"
+ SF-ADJUSTMENT _"Highlight opacity" '(66 0 255 1 10 0 0)
+ SF-COLOR _"Drop shadow color" "black"
+ SF-ADJUSTMENT _"Drop shadow opacity" '(100 0 100 1 10 0 0)
+ SF-ADJUSTMENT _"Drop shadow blur radius" '(12 0 255 1 10 0 1)
+ SF-ADJUSTMENT _"Drop shadow X offset" '(5 0 255 1 10 0 1)
+ SF-ADJUSTMENT _"Drop shadow Y offset" '(5 0 255 1 10 0 1)
+ SF-TOGGLE _"Keep selection" TRUE
+)
+
+(script-fu-menu-register "script-fu-xach-effect"
+ "<Image>/Filters/Light and Shadow/Shadow")
diff --git a/plug-ins/script-fu/tinyscheme/BUILDING b/plug-ins/script-fu/tinyscheme/BUILDING
new file mode 100644
index 0000000..5c00236
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/BUILDING
@@ -0,0 +1,139 @@
+ Building TinyScheme
+ -------------------
+
+The included makefile includes logic for Linux, Solaris and Win32, and can
+readily serve as an example for other OSes, especially Unixes. There are
+a lot of compile-time flags in TinyScheme (preprocessor defines) that can trim
+unwanted features. See next section. 'make all' and 'make clean' function as
+expected.
+
+Autoconfing TinyScheme was once proposed, but the distribution would not be
+so small anymore. There are few platform dependencies in TinyScheme, and in
+general compiles out of the box.
+
+ Customizing
+ -----------
+
+ The following symbols are defined to default values in scheme.h.
+ Use the -D flag of cc to set to either 1 or 0.
+
+ STANDALONE
+ Define this to produce a standalone interpreter.
+
+ USE_MATH
+ Includes math routines.
+
+ USE_CHAR_CLASSIFIERS
+ Includes character classifier procedures.
+
+ USE_ASCII_NAMES
+ Enable extended character notation based on ASCII names.
+
+ USE_STRING_PORTS
+ Enables string ports.
+
+ USE_ERROR_HOOK
+ To force system errors through user-defined error handling.
+ (see "Error handling")
+
+ USE_TRACING
+ To enable use of TRACING.
+
+ USE_COLON_HOOK
+ Enable use of qualified identifiers. (see "Colon Qualifiers - Packages")
+ Defining this as 0 has the rather drastic consequence that any code using
+ packages will stop working, and will have to be modified. It should only
+ be used if you *absolutely* need to use '::' in identifiers.
+
+ USE_STRCASECMP
+ Defines stricmp as strcasecmp, for Unix.
+
+ STDIO_ADDS_CR
+ Informs TinyScheme that stdio translates "\n" to "\r\n". For DOS/Windows.
+
+ USE_DL
+ Enables dynamically loaded routines. If you define this symbol, you
+ should also include dynload.c in your compile.
+
+ USE_PLIST
+ Enables property lists (not Standard Scheme stuff). Off by default.
+
+ USE_NO_FEATURES
+ Shortcut to disable USE_MATH, USE_CHAR_CLASSIFIERS, USE_ASCII_NAMES,
+ USE_STRING_PORTS, USE_ERROR_HOOK, USE_TRACING, USE_COLON_HOOK,
+ USE_DL.
+
+ USE_SCHEME_STACK
+ Enables 'cons' stack (the alternative is a faster calling scheme, which
+ breaks continuations). Undefine it if you don't care about strict compatibility
+ but you do care about faster execution.
+
+
+ OS-X tip
+ --------
+ I don't have access to OS-X, but Brian Maher submitted the following tip:
+
+[1] Download and install fink (I installed fink in
+/usr/local/fink)
+[2] Install the 'dlcompat' package using fink as such:
+> fink install dlcompat
+[3] Make the following changes to the
+tinyscheme-1.32.tar.gz
+
+diff -r tinyscheme-1.32/dynload.c
+tinyscheme-1.32-new/dynload.c
+24c24
+< #define SUN_DL
+---
+>
+Only in tinyscheme-1.32-new/: dynload.o
+Only in tinyscheme-1.32-new/: libtinyscheme.a Only in tinyscheme-1.32-new/: libtinyscheme.so diff -r tinyscheme-1.32/makefile tinyscheme-1.32-new/makefile
+33,34c33,43
+< LD = gcc
+< LDFLAGS = -shared
+---
+> #LD = gcc
+> #LDFLAGS = -shared
+> #DEBUG=-g -Wno-char-subscripts -O
+> #SYS_LIBS= -ldl
+> #PLATFORM_FEATURES= -DSUN_DL=1
+>
+> # Mac OS X
+> CC = gcc
+> CFLAGS = -I/usr/local/fink/include
+> LD = gcc
+> LDFLAGS = -L/usr/local/fink/lib
+37c46
+< PLATFORM_FEATURES= -DSUN_DL=1
+---
+> PLATFORM_FEATURES= -DSUN_DL=1 -DOSX
+60c69
+< $(CC) -I. -c $(DEBUG) $(FEATURES)
+$(DL_FLAGS) $<
+---
+> $(CC) $(CFLAGS) -I. -c $(DEBUG)
+$(FEATURES) $(DL_FLAGS) $<
+66c75
+< $(CC) -o $@ $(DEBUG) $(OBJS) $(SYS_LIBS)
+---
+> $(CC) $(LDFLAGS) -o $@ $(DEBUG) $(OBJS)
+$(SYS_LIBS)
+Only in tinyscheme-1.32-new/: scheme
+diff -r tinyscheme-1.32/scheme.c
+tinyscheme-1.32-new/scheme.c
+60,61c60,61
+< #ifndef macintosh
+< # include <malloc.h>
+---
+> #ifdef OSX
+> /* Do nothing */
+62a63,65
+> # ifndef macintosh
+> # include <malloc.h>
+> # else
+77c80,81
+< #endif /* macintosh */
+---
+> # endif /* macintosh */
+> #endif /* !OSX */
+Only in tinyscheme-1.32-new/: scheme.o
diff --git a/plug-ins/script-fu/tinyscheme/CHANGES b/plug-ins/script-fu/tinyscheme/CHANGES
new file mode 100644
index 0000000..2f7a33a
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/CHANGES
@@ -0,0 +1,326 @@
+Change Log
+----------
+
+Version 1.41
+ Bugs fixed:
+ #3020389 - Added makefile section for Mac OS X (SL)
+ #3286135 - Fixed num_mod routine which caused errors in use of modulo
+ #3290232 - Corrected version number shown on startup (GM)
+ #3394882 - Added missing #if in opdefines.h around get and put (DC)
+ #3395547 - Fix for the modulo procedure (DC)
+ #3400290 - Optimized append to make it an O(n) operation (DC)
+ #3493926 - Corrected flag used when building shared files on OSX (J)
+
+ R5RS related changes:
+ #2866196 - Parser does not handle delimiters correctly
+ #3395548 - Add a decimal point to inexact numbers in atom2str (DC)
+ #3399331 - Make min/max return inexact when any argument is inexact
+ #3399332 - Compatibility fix for expt.
+ #3399335 - Optional radix for string->number and number->string (DC)
+ #3400202 - Append with one argument should not return a list (DC)
+ #3400284 - Compatibility fix for integer?
+
+ Other changes:
+ - Added flags to makefile for MinGW/MSYS (TC)
+ - Moved variable declarations to avoid warnings with some compilers
+ - Don't print space after initial #( when printing vectors.
+ - Minor optimization for is_nonneg().
+ - No need to round integers in OP_ROUND (#3400284)
+ - Fixes to code that reports line number with error (RC)
+
+ Contributors:
+ Kevin Cozens, Gordon McNutt, Doug Currie, Sean Long, Tim Cas, Joey,
+ and Richard Copley, and CMarinier.
+
+Version 1.40
+ Bugs fixed:
+ #1964950 - Stop core dumps due to bad syntax in LET (and variants)
+ #2826594 - allow reverse to work on empty list (Tony Garnock-Jones)
+ Potential problem of arglist to foreign calls being wrongly GC'ed.
+ Fixed bug that read could loop forever (tehom).
+
+ API changes:
+ Exposed is_list and list_length.
+ Added scheme_register_foreign_func_list and declarations for it (tehom)
+ Defined *compile-hook* (tehom)
+
+ Other changes:
+ Updated is_list and list_length to handle circular lists.
+ Nested calling thru C has been made now safer (tehom)
+ Peter Michaux cleaned up port_rep_from_file
+ Added unwind-protect (tehom)
+ Some cleanups to in/outport and Eval_Cycle by Peter Michaux
+ Report error line number (Mostly by Sanel Zukan, back-compatibility by Tehom)
+
+ Contributors:
+ Kevin Cozens, Dimitrios Souflis, Tom Breton, Peter Michaux, Sanel Zukan,
+ and Tony Garnock-Jones.
+
+Version 1.39
+ Bugs fixed:
+ Fix for the load bug
+ Fixed parsing of octal coded characters. Fixes bug #1818018.
+ Added tests for when mk_vector is out of memory. Can't rely on sc->sink.
+ Fix for bug #1794369
+ Finished feature-request 1599947: scheme_apply0 etc return values.
+ Partly provided feature-request 1599947: Expose list_length, eqv, etc
+ Provided feature-request 1599945, Scheme->C->Scheme calling.
+ Fix for bug 1593861 (behavior of is_integer)
+ Fix for bug 1589711
+ Error checking of binding spec syntax in LET and LETREC. The bad syntax
+ was causing a segmentation fault in Linux. Complete fixes for bug #1817986.
+ Error checking of binding spec syntax in LET*
+ Bad syntax was causing core dump in Linux.
+ Fix for nasty gc bug
+
+ R5RS changes:
+ R5RS requires numbers to be of equal value AND of the same type (ie. both
+ exact or inexact) in order to return #t from eqv?. R5RS compliance fix.
+ String output ports now conform to SRFI-6
+
+ Other changes:
+ Drew Yao fixed buffer overflow problems in mk_sharp_const.
+ put OP_T0LVL in charge of reacting to EOF
+ file_push checks array bounds (patch from Ray Lehtiniemi)
+ Changed to always use snprintf (Patch due to Ramiro bsd1628)
+ Updated usage information using text from the Manual.txt file.
+
+Version 1.38
+ Interim release until the rewrite, mostly incorporating modifications
+ from Kevin Cozens. Small addition for Cygwin in the makefile, and
+ modifications by Andrew Guenther for Apple platforms.
+
+Version 1.37
+ Joe Buehler submitted reserve_cells.
+
+Version 1.36
+ Joe Buehler fixed a patch in the allocator.
+ Alexander Shendi moved the comment handling in the scanner, which
+ fixed an obscure bug for which Mike E had provided a patch as well.
+ Kevin Cozens has submitted some fixes and modifications which have
+ not been incorporated yet in their entirety.
+
+Version 1.35
+ Todd Showalter discovered that the number of free cells reported
+ after GC was incorrect, which could also cause unnecessary allocations.
+
+Version 1.34
+ Long missing version. Lots of bugfixes have accumulated in my email, so
+ I had to start using them. In this version, Keenan Pepper has submitted
+ a bugfix for the string comparison library procedure, Wouter Boeke
+ modified some code that was casting to the wrong type and crashed on
+ some machines, "SheppardCo" submitted a replacement "modulo" code and
+ Scott Fenton submitted lots of corrections that shut up some compiler
+ warnings. Brian Maher submitted instructions on how to build on OS-X.
+ I have to dig deeper into my mailbox and find earlier emails, too.
+
+Version 1.33
+ Charles Hayden fixed a nasty GC bug of the new stack frame, while in
+ the process of porting TinyScheme to C++. He also submitted other
+ changes, and other people also had comments or requests, but the GC
+ bug was so important that this version is put through the door to
+ correct it.
+
+Version 1.32
+ Stephen Gildea put some quality time on TinyScheme again, and made
+ a whole lot of changes to the interpreter that made it noticeably
+ faster.
+
+Version 1.31
+ Patches to the hastily-done version 1.30. Stephen Gildea fixed
+ some things done wrongly, and Richard Russo fixed the makefile
+ for building on Windows. Property lists (heritage from MiniScheme)
+ are now optional and have disappeared from the interface. They
+ should be considered as deprecated.
+
+Version 1.30
+ After many months, I followed Preston Bannister's advice of
+ using macros and a single source text to keep the enums and the
+ dispatch table in sync, and I used his contributed "opdefines.h".
+ Timothy Downs contributed a helpful function, "scheme_call".
+ Stephen Gildea contributed new versions of the makefile and
+ practically all other sources. He created a built-in STRING-APPEND,
+ and fixed a lot of other bugs.
+ Ruhi Bloodworth reported fixes necessary for OS X and a small
+ bug in dynload.c.
+
+Version 1.29
+ The previous version contained a lot of corrections, but there
+ were a lot more that still wait on a sheet of paper lost in a
+ carton someplace after my house move... Manuel Heras-Gilsanz
+ noticed this and resent his own contribution, which relies on
+ another bugfix that v.1.28 was missing: a problem with string
+ output, that this version fixes. I hope other people will take
+ the time to resend their contributions, if they didn't make it
+ to v.1.28.
+
+Version 1.28
+ Many people have contacted me with bugfixes or remarks in
+ the three months I was inactive. A lot of them spotted that
+ scheme_deinit crashed while reporting gc results. They suggested
+ that sc->outport be set to NIL in scheme_deinit, which I did.
+ Dennis Taylor remarked that OP_VALUEPRINT reset sc->value instead
+ of preserving it. He submitted a modification which I adopted
+ partially. David Hovemeyer sent me many little changes, that you
+ will find in version 1.28, and Partice Stoessel modified the
+ float reader to conform to R5RS.
+
+Version 1.27
+ Version 1.27 is the successor of 1.25. Bug fixes only, but I had to
+ release them so that everybody can profit. 'Backchar' tried to write
+ back to the string, which obviously didn't work for const strings.
+ 'Substring' didn't check for crossed start and end indices. Defines
+ changed to restore the ability to compile under MSVC.
+
+Version 1.26
+ Version 1.26 was never released. I changed a lot of things, in fact
+ too much, even the garbage collector, and hell broke loose. I'll
+ try a more gradual approach next time.
+
+Version 1.25
+ Types have been homogenized to be able to accommodate a different
+ representation. Plus, promises are no longer closures. Unfortunately,
+ I discovered that continuations and force/delay do not pass the SCM
+ test (and never did)... However, on the bright side, what little
+ modifications I did had a large impact on the footprint:
+ USE_NO_FEATURES now produces an object file of 63960 bytes on Linux!
+
+Version 1.24
+ SCM tests now pass again after change in atom2str.
+
+Version 1.23
+ Finally I managed to mess it up with my version control. Version
+ 1.22 actually lacked some of the things I have been fixing in the
+ meantime. This should be considered as a complete replacement for
+ 1.22.
+
+Version 1.22
+ The new ports had a bug in LOAD. MK_CLOSURE is introduced.
+ Shawn Wagner inquired about string->number and number->string.
+ I added string->atom and atom->string and defined the number
+ functions from them. Doing that, I fixed WRITE applied to symbols
+ (it didn't quote them). Unfortunately, minimum build is now
+ slightly larger than 64k... I postpone action because Jason's idea
+ might solve it elegantly.
+
+Version 1.21
+ Jason Felice submitted a radically different datatype representation
+ which he had implemented. While discussing its pros and cons, it
+ became apparent that the current implementation of ports suffered
+ from a grave fault: ports were not garbage-collected. I changed the
+ ports to be heap-allocated, which enabled the use of string ports
+ for loading. Jason also fixed errors in the garbage collection of
+ vectors. USE_VERBATIM is gone. "ssp_compiler.c" has a better solution
+ on HTML generation. A bug involving backslash notation in strings
+ has been fixed. '-c' flag now executes next argument as a stream of
+ Scheme commands. Foreign functions are now also heap allocated,
+ and scheme_define is used to define everything.
+
+Version 1.20
+ Tracing has been added. The toplevel loop has been slightly
+ rearranged. Backquote reading for vector templates has been
+ sanitized. Symbol interning is now correct. Arithmetic functions
+ have been corrected. APPLY, MAP, FOR-EACH, numeric comparison
+ functions fixed. String reader/writer understands \xAA notation.
+
+Version 1.19
+ Carriage Return now delimits identifiers. DOS-formatted Scheme files
+ can be used by Unix. Random number generator added to library.
+ Fixed some glitches of the new type-checking scheme. Fixed erroneous
+ (append '() 'a) behavior. Will continue with r4rstest.scm to
+ fix errors.
+
+Version 1.18
+ The FFI has been extended. USE_VERBOSE_GC has gone. Anyone wanting
+ the same functionality can put (gcverbose #t) in init.scm.
+ print-width was removed, along with three corresponding op-codes.
+ Extended character constants with ASCII names were added.
+ mk_counted_string paves the way for full support of binary strings.
+ As much as possible of the type-checking chores were delegated
+ to the inner loop, thus reducing the code size to less than 4200 loc!
+
+Version 1.17
+ Dynamically-loaded extensions are more fully integrated.
+ TinyScheme is now distributed under the BSD open-source license.
+
+Version 1.16
+ Dynamically-loaded extensions introduced (USE_DL).
+ Santeri Paavolainen found a race condition: When a cons is executed,
+ and each of the two arguments is a constructing function, GC could
+ happen before all arguments are evaluated and cons() is called, and
+ the evaluated arguments would all be reclaimed!
+ Fortunately, such a case was rare in the code, although it is
+ a pitfall in new code and code in foreign functions. Currently, only
+ one such case remains, when COLON_HOOK is defined.
+
+Version 1.15
+ David Gould also contributed some changes that speed up operation.
+ Kirk Zurell fixed HASPROP.
+ The Garbage Collection didn't collect all the garbage...fixed.
+
+Version 1.14
+ Unfortunately, after Andre fixed the GC it became obvious that the
+ algorithm was too slow... Fortunately, David Gould found a way to
+ speed it up.
+
+Version 1.13
+ Silly bug involving division by zero resolved by Roland Kaufman.
+ Macintoch support from Shmulik Regev.
+ Float parser bug fixed by Alexander Shendi.
+ GC bug from Andru Luvisi.
+
+Version 1.12
+ Cis* incorrectly called isalpha() instead of isascii()
+ Added USE_CHAR_CLASSIFIERS, USE_STRING_PORTS.
+
+Version 1.11
+ BSDI defines isnumber... changed all similar functions to is_*
+ EXPT now has correct definition. Added FLOOR,CEILING,TRUNCATE
+ and ROUND, courtesy of Bengt Kleberg. Preprocessor symbols now
+ have values 1 or 0, and can be set as compiler defines (proposed
+ by Andy Ganor *months* ago). 'prompt' and 'InitFile' can now be
+ defined during compilation, too.
+
+Version 1.10
+ Another bug when file ends with comment!
+ Added DEFINE-MACRO in init.scm, courtesy of Andy Gaynor.
+
+Version 1.09
+ Removed bug when READ met EOF. lcm.
+
+Version 1.08
+ quotient,remainder and modulo. gcd.
+
+Version 1.07
+ '=>' in cond now exists
+ list? now checks for circularity
+ some reader bugs removed
+ Reader is more consistent wrt vectors
+ Quote and Quasiquote work with vectors
+
+Version 1.06
+ #! is now skipped
+ generic-assoc bug removed
+ strings are now managed differently, hack.txt is removed
+ various delicate points fixed
+
+Version 1.05
+ Support for scripts, *args*, "-1" option.
+ Various R5RS procedures.
+ *sharp-hook*
+ Handles unmatched parentheses.
+ New architecture for procedures.
+
+Version 1.04
+ Added missing T_ATOM bits...
+ Added vectors
+ Free-list is sorted by address, since vectors need consecutive cells.
+ (quit <exitcode>) for use with scripts
+
+Version 1.03 (26 Aug 1998):
+ Extended .h with useful functions for FFI
+ Library: with-input-* etc.
+ Finished R5RS I/O, added string ports.
+
+Version 1.02 (25 Aug 1998):
+ First part of R5RS I/O.
diff --git a/plug-ins/script-fu/tinyscheme/COPYING b/plug-ins/script-fu/tinyscheme/COPYING
new file mode 100644
index 0000000..a6c49a2
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/COPYING
@@ -0,0 +1,31 @@
+ LICENSE TERMS
+
+Copyright (c) 2000, Dimitrios Souflis
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+Neither the name of Dimitrios Souflis nor the names of the
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/plug-ins/script-fu/tinyscheme/Makefile.am b/plug-ins/script-fu/tinyscheme/Makefile.am
new file mode 100644
index 0000000..49ce643
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/Makefile.am
@@ -0,0 +1,26 @@
+## Process this file with automake to produce Makefile.in
+
+AM_CFLAGS = \
+ -DSTANDALONE=0 \
+ -DUSE_INTERFACE=1 \
+ -DUSE_MATH=1 \
+ -DUSE_ASCII_NAMES=0 \
+ -DUSE_STRLWR=0 \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS)
+
+noinst_LIBRARIES = libtinyscheme.a
+
+libtinyscheme_a_SOURCES = \
+ scheme.c \
+ opdefines.h \
+ scheme-private.h \
+ scheme.h
+
+EXTRA_DIST = \
+ BUILDING \
+ CHANGES \
+ COPYING \
+ hack.txt \
+ Manual.txt \
+ MiniSCHEMETribute.txt
diff --git a/plug-ins/script-fu/tinyscheme/Makefile.in b/plug-ins/script-fu/tinyscheme/Makefile.in
new file mode 100644
index 0000000..c506dfe
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/Makefile.in
@@ -0,0 +1,924 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plug-ins/script-fu/tinyscheme
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libtinyscheme_a_AR = $(AR) $(ARFLAGS)
+libtinyscheme_a_LIBADD =
+am_libtinyscheme_a_OBJECTS = scheme.$(OBJEXT)
+libtinyscheme_a_OBJECTS = $(am_libtinyscheme_a_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/scheme.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libtinyscheme_a_SOURCES)
+DIST_SOURCES = $(libtinyscheme_a_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp COPYING \
+ README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CFLAGS = \
+ -DSTANDALONE=0 \
+ -DUSE_INTERFACE=1 \
+ -DUSE_MATH=1 \
+ -DUSE_ASCII_NAMES=0 \
+ -DUSE_STRLWR=0 \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS)
+
+noinst_LIBRARIES = libtinyscheme.a
+libtinyscheme_a_SOURCES = \
+ scheme.c \
+ opdefines.h \
+ scheme-private.h \
+ scheme.h
+
+EXTRA_DIST = \
+ BUILDING \
+ CHANGES \
+ COPYING \
+ hack.txt \
+ Manual.txt \
+ MiniSCHEMETribute.txt
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/script-fu/tinyscheme/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/script-fu/tinyscheme/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libtinyscheme.a: $(libtinyscheme_a_OBJECTS) $(libtinyscheme_a_DEPENDENCIES) $(EXTRA_libtinyscheme_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libtinyscheme.a
+ $(AM_V_AR)$(libtinyscheme_a_AR) libtinyscheme.a $(libtinyscheme_a_OBJECTS) $(libtinyscheme_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libtinyscheme.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheme.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/scheme.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/scheme.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/script-fu/tinyscheme/Manual.txt b/plug-ins/script-fu/tinyscheme/Manual.txt
new file mode 100644
index 0000000..7ef62e9
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/Manual.txt
@@ -0,0 +1,452 @@
+
+
+ TinySCHEME Version 1.41
+
+ "Safe if used as prescribed"
+ -- Philip K. Dick, "Ubik"
+
+This software is open source, covered by a BSD-style license.
+Please read accompanying file COPYING.
+-------------------------------------------------------------------------------
+
+ This Scheme interpreter is based on MiniSCHEME version 0.85k4
+ (see miniscm.tar.gz in the Scheme Repository)
+ Original credits in file MiniSCHEMETribute.txt.
+
+ D. Souflis (dsouflis@acm.org)
+
+-------------------------------------------------------------------------------
+ What is TinyScheme?
+ -------------------
+
+ TinyScheme is a lightweight Scheme interpreter that implements as large
+ a subset of R5RS as was possible without getting very large and
+ complicated. It is meant to be used as an embedded scripting interpreter
+ for other programs. As such, it does not offer IDEs or extensive toolkits
+ although it does sport a small top-level loop, included conditionally.
+ A lot of functionality in TinyScheme is included conditionally, to allow
+ developers freedom in balancing features and footprint.
+
+ As an embedded interpreter, it allows multiple interpreter states to
+ coexist in the same program, without any interference between them.
+ Programmatically, foreign functions in C can be added and values
+ can be defined in the Scheme environment. Being a quite small program,
+ it is easy to comprehend, get to grips with, and use.
+
+ Known bugs
+ ----------
+
+ TinyScheme is known to misbehave when memory is exhausted.
+
+
+ Things that keep missing, or that need fixing
+ ---------------------------------------------
+
+ There are no hygienic macros. No rational or
+ complex numbers. No unwind-protect and call-with-values.
+
+ Maybe (a subset of) SLIB will work with TinySCHEME...
+
+ Decent debugging facilities are missing. Only tracing is supported
+ natively.
+
+
+ Scheme Reference
+ ----------------
+
+ If something seems to be missing, please refer to the code and
+ "init.scm", since some are library functions. Refer to the MiniSCHEME
+ readme as a last resort.
+
+ Environments
+ (interaction-environment)
+ See R5RS. In TinySCHEME, immutable list of association lists.
+
+ (current-environment)
+ The environment in effect at the time of the call. An example of its
+ use and its utility can be found in the sample code that implements
+ packages in "init.scm":
+
+ (macro (package form)
+ `(apply (lambda ()
+ ,@(cdr form)
+ (current-environment))))
+
+ The environment containing the (local) definitions inside the closure
+ is returned as an immutable value.
+
+ (defined? <symbol>) (defined? <symbol> <environment>)
+ Checks whether the given symbol is defined in the current (or given)
+ environment.
+
+ Symbols
+ (gensym)
+ Returns a new interned symbol each time. Will probably move to the
+ library when string->symbol is implemented.
+
+ Directives
+ (gc)
+ Performs garbage collection immediately.
+
+ (gcverbose) (gcverbose <bool>)
+ The argument (defaulting to #t) controls whether GC produces
+ visible outcome.
+
+ (quit) (quit <num>)
+ Stops the interpreter and sets the 'retcode' internal field (defaults
+ to 0). When standalone, 'retcode' is returned as exit code to the OS.
+
+ (tracing <num>)
+ 1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1).
+
+ Mathematical functions
+ Since rationals and complexes are absent, the respective functions
+ are also missing.
+ Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling,
+ trunc, round and also sqrt and expt when USE_MATH=1.
+ Number-theoretical quotient, remainder and modulo, gcd, lcm.
+ Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?,
+ exact->inexact. inexact->exact is a core function.
+
+ Type predicates
+ boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?,
+ char?,port?,input-port?,output-port?,procedure?,pair?,environment?',
+ vector?. Also closure?, macro?.
+
+ Types
+ Types supported:
+
+ Numbers (integers and reals)
+ Symbols
+ Pairs
+ Strings
+ Characters
+ Ports
+ Eof object
+ Environments
+ Vectors
+
+ Literals
+ String literals can contain escaped quotes \" as usual, but also
+ \n, \r, \t, \xDD (hex representations) and \DDD (octal representations).
+ Note also that it is possible to include literal newlines in string
+ literals, e.g.
+
+ (define s "String with newline here
+ and here
+ that can function like a HERE-string")
+
+ Character literals contain #\space and #\newline and are supplemented
+ with #\return and #\tab, with obvious meanings. Hex character
+ representations are allowed (e.g. #\x20 is #\space).
+ When USE_ASCII_NAMES is defined, various control characters can be
+ referred to by their ASCII name.
+ 0 #\nul 17 #\dc1
+ 1 #\soh 18 #\dc2
+ 2 #\stx 19 #\dc3
+ 3 #\etx 20 #\dc4
+ 4 #\eot 21 #\nak
+ 5 #\enq 22 #\syn
+ 6 #\ack 23 #\etv
+ 7 #\bel 24 #\can
+ 8 #\bs 25 #\em
+ 9 #\ht 26 #\sub
+ 10 #\lf 27 #\esc
+ 11 #\vt 28 #\fs
+ 12 #\ff 29 #\gs
+ 13 #\cr 30 #\rs
+ 14 #\so 31 #\us
+ 15 #\si
+ 16 #\dle 127 #\del
+
+ Numeric literals support #x #o #b and #d. Flonums are currently read only
+ in decimal notation. Full grammar will be supported soon.
+
+ Quote, quasiquote etc.
+ As usual.
+
+ Immutable values
+ Immutable pairs cannot be modified by set-car! and set-cdr!.
+ Immutable strings cannot be modified via string-set!
+
+ I/O
+ As per R5RS, plus String Ports (see below).
+ current-input-port, current-output-port,
+ close-input-port, close-output-port, input-port?, output-port?,
+ open-input-file, open-output-file.
+ read, write, display, newline, write-char, read-char, peek-char.
+ char-ready? returns #t only for string ports, because there is no
+ portable way in stdio to determine if a character is available.
+ Also open-input-output-file, set-input-port, set-output-port (not R5RS)
+ Library: call-with-input-file, call-with-output-file,
+ with-input-from-file, with-output-from-file and
+ with-input-output-from-to-files, close-port and input-output-port?
+ (not R5RS).
+ String Ports: open-input-string, open-output-string, get-output-string,
+ open-input-output-string. Strings can be used with I/O routines.
+
+ Vectors
+ make-vector, vector, vector-length, vector-ref, vector-set!, list->vector,
+ vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS)
+
+ Strings
+ string, make-string, list->string, string-length, string-ref, string-set!,
+ substring, string->list, string-fill!, string-append, string-copy.
+ string=?, string<?, string>?, string>?, string<=?, string>=?.
+ (No string-ci*? yet). string->number, number->string. Also atom->string,
+ string->atom (not R5RS).
+
+ Symbols
+ symbol->string, string->symbol
+
+ Characters
+ integer->char, char->integer.
+ char=?, char<?, char>?, char<=?, char>=?.
+ (No char-ci*?)
+
+ Pairs & Lists
+ cons, car, cdr, list, length, map, for-each, foldr, list-tail,
+ list-ref, last-pair, reverse, append.
+ Also member, memq, memv, based on generic-member, assoc, assq, assv
+ based on generic-assoc.
+
+ Streams
+ head, tail, cons-stream
+
+ Control features
+ Apart from procedure?, also macro? and closure?
+ map, for-each, force, delay, call-with-current-continuation (or call/cc),
+ eval, apply. 'Forcing' a value that is not a promise produces the value.
+ There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in
+ the presence of continuations would require support from the abstract
+ machine itself.
+
+ Property lists
+ TinyScheme inherited from MiniScheme property lists for symbols.
+ put, get.
+
+ Dynamically-loaded extensions
+ (load-extension <filename without extension>)
+ Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use
+ of the ld.so.conf file or the LD_RUN_PATH system variable in order to place
+ the library in a directory other than the current one. Please refer to the
+ appropriate 'man' page.
+
+ Esoteric procedures
+ (oblist)
+ Returns the oblist, an immutable list of all the symbols.
+
+ (macro-expand <form>)
+ Returns the expanded form of the macro call denoted by the argument
+
+ (define-with-return (<procname> <args>...) <body>)
+ Like plain 'define', but makes the continuation available as 'return'
+ inside the procedure. Handy for imperative programs.
+
+ (new-segment <num>)
+ Allocates more memory segments.
+
+ defined?
+ See "Environments"
+
+ (get-closure-code <closure>)
+ Gets the code as scheme data.
+
+ (make-closure <code> <environment>)
+ Makes a new closure in the given environment.
+
+ Obsolete procedures
+ (print-width <object>)
+
+ Programmer's Reference
+ ----------------------
+
+ The interpreter state is initialized with "scheme_init".
+ Custom memory allocation routines can be installed with an alternate
+ initialization function: "scheme_init_custom_alloc".
+ Files can be loaded with "scheme_load_file". Strings containing Scheme
+ code can be loaded with "scheme_load_string". It is a good idea to
+ "scheme_load" init.scm before anything else.
+
+ External data for keeping external state (of use to foreign functions)
+ can be installed with "scheme_set_external_data".
+ Foreign functions are installed with "assign_foreign". Additional
+ definitions can be added to the interpreter state, with "scheme_define"
+ (this is the way HTTP header data and HTML form data are passed to the
+ Scheme script in the Altera SQL Server). If you wish to define the
+ foreign function in a specific environment (to enhance modularity),
+ use "assign_foreign_env".
+
+ The procedure "scheme_apply0" has been added with persistent scripts in
+ mind. Persistent scripts are loaded once, and every time they are needed
+ to produce HTTP output, appropriate data are passed through global
+ definitions and function "main" is called to do the job. One could
+ add easily "scheme_apply1" etc.
+
+ The interpreter state should be deinitialized with "scheme_deinit".
+
+ DLLs containing foreign functions should define a function named
+ init_<base-name>. E.g. foo.dll should define init_foo, and bar.so
+ should define init_bar. This function should assign_foreign any foreign
+ function contained in the DLL.
+
+ The first dynamically loaded extension available for TinyScheme is
+ a regular expression library. Although it's by no means an
+ established standard, this library is supposed to be installed in
+ a directory mirroring its name under the TinyScheme location.
+
+
+ Foreign Functions
+ -----------------
+
+ The user can add foreign functions in C. For example, a function
+ that squares its argument:
+
+ pointer square(scheme *sc, pointer args) {
+ if(args!=sc->NIL) {
+ if(sc->isnumber(sc->pair_car(args))) {
+ double v=sc->rvalue(sc->pair_car(args));
+ return sc->mk_real(sc,v*v);
+ }
+ }
+ return sc->NIL;
+ }
+
+ Foreign functions are now defined as closures:
+
+ sc->interface->scheme_define(
+ sc,
+ sc->global_env,
+ sc->interface->mk_symbol(sc,"square"),
+ sc->interface->mk_foreign_func(sc, square));
+
+
+ Foreign functions can use the external data in the "scheme" struct
+ to implement any kind of external state.
+
+ External data are set with the following function:
+ void scheme_set_external_data(scheme *sc, void *p);
+
+ As of v.1.17, the canonical way for a foreign function in a DLL to
+ manipulate Scheme data is using the function pointers in sc->interface.
+
+ Standalone
+ ----------
+
+ Usage: tinyscheme -?
+ or: tinyscheme [<file1> <file2> ...]
+ followed by
+ -1 <file> [<arg1> <arg2> ...]
+ -c <Scheme commands> [<arg1> <arg2> ...]
+ assuming that the executable is named tinyscheme.
+
+ Use - in the place of a filename to denote stdin.
+ The -1 flag is meant for #! usage in shell scripts. If you specify
+ #! /somewhere/tinyscheme -1
+ then tinyscheme will be called to process the file. For example, the
+ following script echoes the Scheme list of its arguments.
+
+ #! /somewhere/tinyscheme -1
+ (display *args*)
+
+ The -c flag permits execution of arbitrary Scheme code.
+
+
+ Error Handling
+ --------------
+
+ Errors are recovered from without damage. The user can install his
+ own handler for system errors, by defining *error-hook*. Defining
+ to '() gives the default behavior, which is equivalent to "error".
+ USE_ERROR_HOOK must be defined.
+
+ A simple exception handling mechanism can be found in "init.scm".
+ A new syntactic form is introduced:
+
+ (catch <expr returned exceptionally>
+ <expr1> <expr2> ... <exprN>)
+
+ "Catch" establishes a scope spanning multiple call-frames
+ until another "catch" is encountered.
+
+ Exceptions are thrown with:
+
+ (throw "message")
+
+ If used outside a (catch ...), reverts to (error "message").
+
+ Example of use:
+
+ (define (foo x) (write x) (newline) (/ x 0))
+
+ (catch (begin (display "Error!\n") 0)
+ (write "Before foo ... ")
+ (foo 5)
+ (write "After foo"))
+
+ The exception mechanism can be used even by system errors, by
+
+ (define *error-hook* throw)
+
+ which makes use of the error hook described above.
+
+ If necessary, the user can devise his own exception mechanism with
+ tagged exceptions etc.
+
+
+ Reader extensions
+ -----------------
+
+ When encountering an unknown character after '#', the user-specified
+ procedure *sharp-hook* (if any), is called to read the expression.
+ This can be used to extend the reader to handle user-defined constants
+ or whatever. It should be a procedure without arguments, reading from
+ the current input port (which will be the load-port).
+
+
+ Colon Qualifiers - Packages
+ ---------------------------
+
+ When USE_COLON_HOOK=1:
+ The lexer now recognizes the construction <qualifier>::<symbol> and
+ transforms it in the following manner (T is the transformation function):
+
+ T(<qualifier>::<symbol>) = (*colon-hook* 'T(<symbol>) <qualifier>)
+
+ where <qualifier> is a symbol not containing any double-colons.
+
+ As the definition is recursive, qualifiers can be nested.
+ The user can define his own *colon-hook*, to handle qualified names.
+ By default, "init.scm" defines *colon-hook* as EVAL. Consequently,
+ the qualifier must denote a Scheme environment, such as one returned
+ by (interaction-environment). "Init.scm" defines a new syntantic form,
+ PACKAGE, as a simple example. It is used like this:
+
+ (define toto
+ (package
+ (define foo 1)
+ (define bar +)))
+
+ foo ==> Error, "foo" undefined
+ (eval 'foo) ==> Error, "foo" undefined
+ (eval 'foo toto) ==> 1
+ toto::foo ==> 1
+ ((eval 'bar toto) 2 (eval 'foo toto)) ==> 3
+ (toto::bar 2 toto::foo) ==> 3
+ (eval (bar 2 foo) toto) ==> 3
+
+ If the user installs another package infrastructure, he must define
+ a new 'package' procedure or macro to retain compatibility with supplied
+ code.
+
+ Note: Older versions used ':' as a qualifier. Unfortunately, the use
+ of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially
+ precludes its use as a real qualifier.
+
+
+
+
+
+
+
+
diff --git a/plug-ins/script-fu/tinyscheme/MiniSCHEMETribute.txt b/plug-ins/script-fu/tinyscheme/MiniSCHEMETribute.txt
new file mode 100644
index 0000000..185f0ec
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/MiniSCHEMETribute.txt
@@ -0,0 +1,88 @@
+ TinyScheme would not exist if it wasn't for MiniScheme. I had just
+ written the HTTP server for Ovrimos SQL Server, and I was lamenting the
+ lack of a scripting language. Server-side Javascript would have been the
+ preferred solution, had there been a Javascript interpreter I could
+ lay my hands on. But there weren't. Perl would have been another solution,
+ but it was probably ten times bigger that the program it was supposed to
+ be embedded in. There would also be thorny licencing issues.
+
+ So, the obvious thing to do was find a truly small interpreter. Forth
+ was a language I had once quasi-implemented, but the difficulty of
+ handling dynamic data and the weirdness of the language put me off. I then
+ looked around for a LISP interpreter, the next thing I knew was easy to
+ implement. Alas, the LeLisp I knew from my days in UPMC (Universite Pierre
+ et Marie Curie) had given way to Common Lisp, a megalith of a language!
+ Then my search lead me to Scheme, a language I knew was very orthogonal
+ and clean. When I found Mini-Scheme, a single C file of some 2400 loc, I
+ fell in love with it! What if it lacked floating-point numbers and
+ strings! The rest, as they say, is history.
+
+ Below are the original credits. Don't email Akira KIDA, the address has
+ changed.
+
+ ---------- Mini-Scheme Interpreter Version 0.85 ----------
+
+ coded by Atsushi Moriwaki (11/5/1989)
+
+ E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
+
+ THIS SOFTWARE IS IN THE PUBLIC DOMAIN
+ ------------------------------------
+ This software is completely free to copy, modify and/or re-distribute.
+ But I would appreciate it if you left my name on the code as the author.
+
+ This version has been modified by R.C. Secrist.
+
+ Mini-Scheme is now maintained by Akira KIDA.
+
+ This is a revised and modified version by Akira KIDA.
+ current version is 0.85k4 (15 May 1994)
+
+ Please send suggestions, bug reports and/or requests to:
+ <SDI00379@niftyserve.or.jp>
+
+
+ Features compared to MiniSCHEME
+ -------------------------------
+
+ All code is now reentrant. Interpreter state is held in a 'scheme'
+ struct, and many interpreters can coexist in the same program, possibly
+ in different threads. The user can specify user-defined memory allocation
+ primitives. (see "Programmer's Reference")
+
+ The reader is more consistent.
+
+ Strings, characters and flonums are supported. (see "Types")
+
+ Files being loaded can be nested up to some depth.
+
+ R5RS I/O is there, plus String Ports. (see "Scheme Reference","I/O")
+
+ Vectors exist.
+
+ As a standalone application, it supports command-line arguments.
+ (see "Standalone")
+
+ Running out of memory is now handled.
+
+ The user can add foreign functions in C. (see "Foreign Functions")
+
+ The code has been changed slightly, core functions have been moved
+ to the library, behavior has been aligned with R5RS etc.
+
+ Support has been added for user-defined error recovery.
+ (see "Error Handling")
+
+ Support has been added for modular programming.
+ (see "Colon Qualifiers - Packages")
+
+ To enable this, EVAL has changed internally, and can
+ now take two arguments, as per R5RS. Environments are supported.
+ (see "Colon Qualifiers - Packages")
+
+ Promises are now evaluated once only.
+
+ (macro (foo form) ...) is now equivalent to (macro foo (lambda(form) ...))
+
+ The reader can be extended using new #-expressions
+ (see "Reader extensions")
diff --git a/plug-ins/script-fu/tinyscheme/README b/plug-ins/script-fu/tinyscheme/README
new file mode 100644
index 0000000..4411119
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/README
@@ -0,0 +1,14 @@
+This directory contains a version of TinyScheme which has been modified
+to support UTF-8 coded strings. The strings stored in a data cell are
+expected to be in UTF-8 format. This allows the continued use of gchar
+pointers to pass around the strings. Processing the strings will require
+conversion to unicode at times depending on the specific operation that
+needs to be done on the UTF-8 coded strings.
+
+The string length value stored in a data cell is the length in bytes of that
+string including the terminating NUL.
+
+Routines that want a string length for a UTF-8 coded string will be passed
+the number of characters and not the number of bytes. If the number of bytes
+is needed, the normal call to strlen() will work.
+
diff --git a/plug-ins/script-fu/tinyscheme/hack.txt b/plug-ins/script-fu/tinyscheme/hack.txt
new file mode 100644
index 0000000..6aba7a7
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/hack.txt
@@ -0,0 +1,233 @@
+
+ How to hack TinyScheme
+ ----------------------
+
+ TinyScheme is easy to learn and modify. It is structured like a
+ meta-interpreter, only it is written in C. All data are Scheme
+ objects, which facilitates both understanding/modifying the
+ code and reifying the interpreter workings.
+
+ In place of a dry description, we will pace through the addition
+ of a useful new datatype: garbage-collected memory blocks.
+ The interface will be:
+
+ (make-block <n> [<fill>]) makes a new block of the specified size
+ optionally filling it with a specified byte
+ (block? <obj>)
+ (block-length <block>)
+ (block-ref <block> <index>) retrieves byte at location
+ (block-set! <block> <index> <byte>) modifies byte at location
+
+ In the sequel, lines that begin with '>' denote lines to add to the
+ code. Lines that begin with '|' are just citations of existing code.
+ Lines that begin with X are deleted.
+
+ First of all, we need to assign a typeid to our new type. Typeids
+ in TinyScheme are small integers declared in an enum, very close to
+ the top of scheme.c; it begins with T_STRING. Add a new one before the
+ end, call it T_MEMBLOCK. Adjust T_LAST_SYSTEM_TYPE.
+
+| T_ENVIRONMENT=14,
+X T_LAST_SYSTEM_TYPE=14
+> T_MEMBLOCK=15,
+> T_LAST_SYSTEM_TYPE=15
+| };
+
+ Then, some helper macros would be useful. Go to where is_string() and
+ the rest are defined and define:
+
+> int is_memblock(pointer p) { return (type(p)==T_MEMBLOCK); }
+
+ This actually is a function, because it is meant to be exported by
+ scheme.h. If no foreign function will ever manipulate a memory block,
+ you can instead define it as a macro
+
+> #define is_memblock(p) (type(p)==T_MEMBLOCK)
+
+ Then we make space for the new type in the main data structure:
+ struct cell. As it happens, the _string part of the union _object
+ (that is used to hold character strings) has two fields that suit us:
+
+| struct {
+| char *_svalue;
+| int _keynum;
+| } _string;
+
+ We can use _svalue to hold the actual pointer and _keynum to hold its
+ length. If we couldn't reuse existing fields, we could always add other
+ alternatives in union _object.
+
+ We then proceed to write the function that actually makes a new block.
+ For conformance reasons, we name it mk_memblock
+
+> static pointer mk_memblock(scheme *sc, int len, char fill) {
+> pointer x;
+> char *p=(char*)sc->malloc(len);
+>
+> if(p==0) {
+> return sc->NIL;
+> }
+> x = get_cell(sc, sc->NIL, sc->NIL);
+>
+> typeflag(x) = T_MEMBLOCK|T_ATOM;
+> strvalue(x)=p;
+> keynum(x)=len;
+> memset(p,fill,len);
+> return (x);
+> }
+
+ The memory used by the MEMBLOCK will have to be freed when the cell
+ is reclaimed during garbage collection. There is a placeholder for
+ that staff, function finalize_cell(), currently handling strings only.
+
+| static void finalize_cell(scheme *sc, pointer a) {
+| if(is_string(a)) {
+| sc->free(strvalue(a));
+> else if(is_memblock(a)) {
+> sc->free(strvalue(a));
+| } else if(is_port(a)) {
+
+ There are no MEMBLOCK literals, so we don't concern ourselves with
+ the READER part (yet!). We must cater to the PRINTER, though. We
+ add one case more in atom2str().
+
+| } else if (is_foreign(l)) {
+| p = sc->strbuff;
+| snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
+> } else if (ismemblock(l)) {
+> p = "#<MEMBLOCK>";
+| } else if (is_continuation(l)) {
+| p = "#<CONTINUATION>";
+| } else {
+
+ Whenever a MEMBLOCK is displayed, it will look like that.
+
+ Now, we must add the interface functions: constructor, predicate,
+ accessor, modifier. We must in fact create new op-codes for the
+ virtual machine underlying TinyScheme. Since version 1.30, TinyScheme
+ uses macros and a single source text to keep the enums and the
+ dispatch table in sync. That's where the op-codes are declared. Note
+ that the opdefines.h file uses unusually long lines to accommodate
+ all the information; adjust your editor to handle this. The file has
+ six columns: A to Z. they contain:
+ - Column A is the name of a routine to handle the scheme function.
+ - Column B is the name the scheme function.
+ - Columns C and D are the minimum and maximum number of arguments
+ that are accepted by the scheme function.
+ - Column E is a set of flags that are used when the interpreter
+ verifies that the passed parameters are of the correct type.
+ - Column F is used to create a set of enums. The enum is used in a
+ switch in the routine listed in column A to get to the code that
+ does the work needed for the scheme function.
+ For reasons of cohesion, we add the new op-codes right after those
+ for vectors:
+
+| _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
+> _OP_DEF(opexe_2, "make-block", 1, 2, TST_NATURAL TST_CHAR, OP_MKBLOCK )
+> _OP_DEF(opexe_2, "block-length", 1, 1, T_MEMBLOCK, OP_BLOCKLEN )
+> _OP_DEF(opexe_2, "block-ref", 2, 2, T_MEMBLOCK TST_NATURAL, OP_BLOCKREF )
+> _OP_DEF(opexe_2, "block-set!", 1, 1, T_MEMBLOCK TST_NATURAL TST_CHAR, OP_BLOCKSET )
+| _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
+
+ We add the predicate along the other predicates:
+
+| _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
+> _OP_DEF(opexe_3, "block?", 1, 1, TST_ANY, OP_BLOCKP )
+| _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
+
+ All that remains is to write the actual processing in opexe_2, right
+ after OP_VECSET.
+
+> case OP_MKBLOCK: { /* make-block */
+> int fill=0;
+> int len;
+>
+> if(!isnumber(car(sc->args))) {
+> Error_1(sc,"make-block: not a number:",car(sc->args));
+> }
+> len=ivalue(car(sc->args));
+> if(len<=0) {
+> Error_1(sc,"make-block: not positive:",car(sc->args));
+> }
+>
+> if(cdr(sc->args)!=sc->NIL) {
+> if(!isnumber(cadr(sc->args)) || ivalue(cadr(sc->args))<0) {
+> Error_1(sc,"make-block: not a positive number:",cadr(sc->args));
+> }
+> fill=charvalue(cadr(sc->args))%255;
+> }
+> s_return(sc,mk_memblock(sc,len,(char)fill));
+> }
+>
+> case OP_BLOCKLEN: /* block-length */
+> if(!ismemblock(car(sc->args))) {
+> Error_1(sc,"block-length: not a memory block:",car(sc->args));
+> }
+> s_return(sc,mk_integer(sc,keynum(car(sc->args))));
+>
+> case OP_BLOCKREF: { /* block-ref */
+> char *str;
+> int index;
+>
+> if(!ismemblock(car(sc->args))) {
+> Error_1(sc,"block-ref: not a memory block:",car(sc->args));
+> }
+> str=strvalue(car(sc->args));
+>
+> if(cdr(sc->args)==sc->NIL) {
+> Error_0(sc,"block-ref: needs two arguments");
+> }
+> if(!isnumber(cadr(sc->args))) {
+> Error_1(sc,"block-ref: not a number:",cadr(sc->args));
+> }
+> index=ivalue(cadr(sc->args));
+>
+> if(index<0 || index>=keynum(car(sc->args))) {
+> Error_1(sc,"block-ref: out of bounds:",cadr(sc->args));
+> }
+>
+> s_return(sc,mk_integer(sc,str[index]));
+> }
+>
+> case OP_BLOCKSET: { /* block-set! */
+> char *str;
+> int index;
+> int c;
+>
+> if(!ismemblock(car(sc->args))) {
+> Error_1(sc,"block-set!: not a memory block:",car(sc->args));
+> }
+> if(isimmutable(car(sc->args))) {
+> Error_1(sc,"block-set!: unable to alter immutable memory block:",car(sc->args));
+> }
+> str=strvalue(car(sc->args));
+>
+> if(cdr(sc->args)==sc->NIL) {
+> Error_0(sc,"block-set!: needs three arguments");
+> }
+> if(!isnumber(cadr(sc->args))) {
+> Error_1(sc,"block-set!: not a number:",cadr(sc->args));
+> }
+> index=ivalue(cadr(sc->args));
+> if(index<0 || index>=keynum(car(sc->args))) {
+> Error_1(sc,"block-set!: out of bounds:",cadr(sc->args));
+> }
+>
+> if(cddr(sc->args)==sc->NIL) {
+> Error_0(sc,"block-set!: needs three arguments");
+> }
+> if(!isinteger(caddr(sc->args))) {
+> Error_1(sc,"block-set!: not an integer:",caddr(sc->args));
+> }
+> c=ivalue(caddr(sc->args))%255;
+>
+> str[index]=(char)c;
+> s_return(sc,car(sc->args));
+> }
+
+ Same for the predicate in opexe_3.
+
+| case OP_VECTORP: /* vector? */
+| s_retbool(isvector(car(sc->args)));
+> case OP_BLOCKP: /* block? */
+> s_retbool(ismemblock(car(sc->args)));
diff --git a/plug-ins/script-fu/tinyscheme/opdefines.h b/plug-ins/script-fu/tinyscheme/opdefines.h
new file mode 100644
index 0000000..ceb4d0e
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/opdefines.h
@@ -0,0 +1,195 @@
+ _OP_DEF(opexe_0, "load", 1, 1, TST_STRING, OP_LOAD )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T0LVL )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T1LVL )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_READ_INTERNAL )
+ _OP_DEF(opexe_0, "gensym", 0, 0, 0, OP_GENSYM )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_VALUEPRINT )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_EVAL )
+#if USE_TRACING
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_EVAL )
+#endif
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E0ARGS )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E1ARGS )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_APPLY )
+#if USE_TRACING
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_APPLY )
+ _OP_DEF(opexe_0, "tracing", 1, 1, TST_NATURAL, OP_TRACING )
+#endif
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DOMACRO )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA1 )
+ _OP_DEF(opexe_0, "make-closure", 1, 2, TST_PAIR TST_ENVIRONMENT, OP_MKCLOSURE )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_QUOTE )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF0 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF1 )
+ _OP_DEF(opexe_0, "defined?", 1, 2, TST_SYMBOL TST_ENVIRONMENT, OP_DEFP )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_BEGIN )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF0 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF1 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET0 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET1 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2 )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0AST )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1AST )
+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2AST )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET0REC )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET1REC )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET2REC )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND0 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND1 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_DELAY )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND0 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND1 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR0 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR1 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C0STREAM )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C1STREAM )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO0 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO1 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE0 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE1 )
+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE2 )
+ _OP_DEF(opexe_1, "eval", 1, 2, TST_ANY TST_ENVIRONMENT, OP_PEVAL )
+ _OP_DEF(opexe_1, "apply", 1, INF_ARG, TST_NONE, OP_PAPPLY )
+ _OP_DEF(opexe_1, "call-with-current-continuation", 1, 1, TST_NONE, OP_CONTINUATION )
+#if USE_MATH
+ _OP_DEF(opexe_2, "inexact->exact", 1, 1, TST_NUMBER, OP_INEX2EX )
+ _OP_DEF(opexe_2, "exp", 1, 1, TST_NUMBER, OP_EXP )
+ _OP_DEF(opexe_2, "log", 1, 1, TST_NUMBER, OP_LOG )
+ _OP_DEF(opexe_2, "sin", 1, 1, TST_NUMBER, OP_SIN )
+ _OP_DEF(opexe_2, "cos", 1, 1, TST_NUMBER, OP_COS )
+ _OP_DEF(opexe_2, "tan", 1, 1, TST_NUMBER, OP_TAN )
+ _OP_DEF(opexe_2, "asin", 1, 1, TST_NUMBER, OP_ASIN )
+ _OP_DEF(opexe_2, "acos", 1, 1, TST_NUMBER, OP_ACOS )
+ _OP_DEF(opexe_2, "atan", 1, 2, TST_NUMBER, OP_ATAN )
+ _OP_DEF(opexe_2, "sqrt", 1, 1, TST_NUMBER, OP_SQRT )
+ _OP_DEF(opexe_2, "expt", 2, 2, TST_NUMBER, OP_EXPT )
+ _OP_DEF(opexe_2, "floor", 1, 1, TST_NUMBER, OP_FLOOR )
+ _OP_DEF(opexe_2, "ceiling", 1, 1, TST_NUMBER, OP_CEILING )
+ _OP_DEF(opexe_2, "truncate", 1, 1, TST_NUMBER, OP_TRUNCATE )
+ _OP_DEF(opexe_2, "round", 1, 1, TST_NUMBER, OP_ROUND )
+#endif
+ _OP_DEF(opexe_2, "+", 0, INF_ARG, TST_NUMBER, OP_ADD )
+ _OP_DEF(opexe_2, "-", 1, INF_ARG, TST_NUMBER, OP_SUB )
+ _OP_DEF(opexe_2, "*", 0, INF_ARG, TST_NUMBER, OP_MUL )
+ _OP_DEF(opexe_2, "/", 1, INF_ARG, TST_NUMBER, OP_DIV )
+ _OP_DEF(opexe_2, "quotient", 1, INF_ARG, TST_INTEGER, OP_INTDIV )
+ _OP_DEF(opexe_2, "remainder", 2, 2, TST_INTEGER, OP_REM )
+ _OP_DEF(opexe_2, "modulo", 2, 2, TST_INTEGER, OP_MOD )
+ _OP_DEF(opexe_2, "car", 1, 1, TST_PAIR, OP_CAR )
+ _OP_DEF(opexe_2, "cdr", 1, 1, TST_PAIR, OP_CDR )
+ _OP_DEF(opexe_2, "cons", 2, 2, TST_NONE, OP_CONS )
+ _OP_DEF(opexe_2, "set-car!", 2, 2, TST_PAIR TST_ANY, OP_SETCAR )
+ _OP_DEF(opexe_2, "set-cdr!", 2, 2, TST_PAIR TST_ANY, OP_SETCDR )
+ _OP_DEF(opexe_2, "char->integer", 1, 1, TST_CHAR, OP_CHAR2INT )
+ _OP_DEF(opexe_2, "integer->char", 1, 1, TST_NATURAL, OP_INT2CHAR )
+ _OP_DEF(opexe_2, "char-upcase", 1, 1, TST_CHAR, OP_CHARUPCASE )
+ _OP_DEF(opexe_2, "char-downcase", 1, 1, TST_CHAR, OP_CHARDNCASE )
+ _OP_DEF(opexe_2, "symbol->string", 1, 1, TST_SYMBOL, OP_SYM2STR )
+ _OP_DEF(opexe_2, "atom->string", 1, 2, TST_ANY TST_NATURAL, OP_ATOM2STR )
+ _OP_DEF(opexe_2, "string->symbol", 1, 1, TST_STRING, OP_STR2SYM )
+ _OP_DEF(opexe_2, "string->atom", 1, 2, TST_STRING TST_NATURAL, OP_STR2ATOM )
+ _OP_DEF(opexe_2, "make-string", 1, 2, TST_NATURAL TST_CHAR, OP_MKSTRING )
+ _OP_DEF(opexe_2, "string-length", 1, 1, TST_STRING, OP_STRLEN )
+ _OP_DEF(opexe_2, "string-ref", 2, 2, TST_STRING TST_NATURAL, OP_STRREF )
+ _OP_DEF(opexe_2, "string-set!", 3, 3, TST_STRING TST_NATURAL TST_CHAR, OP_STRSET )
+ _OP_DEF(opexe_2, "string-append", 0, INF_ARG, TST_STRING, OP_STRAPPEND )
+ _OP_DEF(opexe_2, "substring", 2, 3, TST_STRING TST_NATURAL, OP_SUBSTR )
+ _OP_DEF(opexe_2, "vector", 0, INF_ARG, TST_NONE, OP_VECTOR )
+ _OP_DEF(opexe_2, "make-vector", 1, 2, TST_NATURAL TST_ANY, OP_MKVECTOR )
+ _OP_DEF(opexe_2, "vector-length", 1, 1, TST_VECTOR, OP_VECLEN )
+ _OP_DEF(opexe_2, "vector-ref", 2, 2, TST_VECTOR TST_NATURAL, OP_VECREF )
+ _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
+ _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
+ _OP_DEF(opexe_3, "boolean?", 1, 1, TST_NONE, OP_BOOLP )
+ _OP_DEF(opexe_3, "eof-object?", 1, 1, TST_NONE, OP_EOFOBJP )
+ _OP_DEF(opexe_3, "null?", 1, 1, TST_NONE, OP_NULLP )
+ _OP_DEF(opexe_3, "=", 2, INF_ARG, TST_NUMBER, OP_NUMEQ )
+ _OP_DEF(opexe_3, "<", 2, INF_ARG, TST_NUMBER, OP_LESS )
+ _OP_DEF(opexe_3, ">", 2, INF_ARG, TST_NUMBER, OP_GRE )
+ _OP_DEF(opexe_3, "<=", 2, INF_ARG, TST_NUMBER, OP_LEQ )
+ _OP_DEF(opexe_3, ">=", 2, INF_ARG, TST_NUMBER, OP_GEQ )
+ _OP_DEF(opexe_3, "symbol?", 1, 1, TST_ANY, OP_SYMBOLP )
+ _OP_DEF(opexe_3, "number?", 1, 1, TST_ANY, OP_NUMBERP )
+ _OP_DEF(opexe_3, "string?", 1, 1, TST_ANY, OP_STRINGP )
+ _OP_DEF(opexe_3, "integer?", 1, 1, TST_ANY, OP_INTEGERP )
+ _OP_DEF(opexe_3, "real?", 1, 1, TST_ANY, OP_REALP )
+ _OP_DEF(opexe_3, "char?", 1, 1, TST_ANY, OP_CHARP )
+#if USE_CHAR_CLASSIFIERS
+ _OP_DEF(opexe_3, "char-alphabetic?", 1, 1, TST_CHAR, OP_CHARAP )
+ _OP_DEF(opexe_3, "char-numeric?", 1, 1, TST_CHAR, OP_CHARNP )
+ _OP_DEF(opexe_3, "char-whitespace?", 1, 1, TST_CHAR, OP_CHARWP )
+ _OP_DEF(opexe_3, "char-upper-case?", 1, 1, TST_CHAR, OP_CHARUP )
+ _OP_DEF(opexe_3, "char-lower-case?", 1, 1, TST_CHAR, OP_CHARLP )
+#endif
+ _OP_DEF(opexe_3, "port?", 1, 1, TST_ANY, OP_PORTP )
+ _OP_DEF(opexe_3, "input-port?", 1, 1, TST_ANY, OP_INPORTP )
+ _OP_DEF(opexe_3, "output-port?", 1, 1, TST_ANY, OP_OUTPORTP )
+ _OP_DEF(opexe_3, "procedure?", 1, 1, TST_ANY, OP_PROCP )
+ _OP_DEF(opexe_3, "pair?", 1, 1, TST_ANY, OP_PAIRP )
+ _OP_DEF(opexe_3, "list?", 1, 1, TST_ANY, OP_LISTP )
+ _OP_DEF(opexe_3, "environment?", 1, 1, TST_ANY, OP_ENVP )
+ _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
+ _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
+ _OP_DEF(opexe_3, "eqv?", 2, 2, TST_ANY, OP_EQV )
+ _OP_DEF(opexe_4, "force", 1, 1, TST_ANY, OP_FORCE )
+ _OP_DEF(opexe_4, 0, 0, 0, 0, OP_SAVE_FORCED )
+ _OP_DEF(opexe_4, "write", 1, 2, TST_ANY TST_OUTPORT, OP_WRITE )
+ _OP_DEF(opexe_4, "write-char", 1, 2, TST_CHAR TST_OUTPORT, OP_WRITE_CHAR )
+ _OP_DEF(opexe_4, "display", 1, 2, TST_ANY TST_OUTPORT, OP_DISPLAY )
+ _OP_DEF(opexe_4, "newline", 0, 1, TST_OUTPORT, OP_NEWLINE )
+ _OP_DEF(opexe_4, "error", 1, INF_ARG, TST_NONE, OP_ERR0 )
+ _OP_DEF(opexe_4, 0, 0, 0, 0, OP_ERR1 )
+ _OP_DEF(opexe_4, "reverse", 1, 1, TST_LIST, OP_REVERSE )
+ _OP_DEF(opexe_4, "list*", 1, INF_ARG, TST_NONE, OP_LIST_STAR )
+ _OP_DEF(opexe_4, "append", 0, INF_ARG, TST_NONE, OP_APPEND )
+#if USE_PLIST
+ _OP_DEF(opexe_4, "put", 3, 3, TST_NONE, OP_PUT )
+ _OP_DEF(opexe_4, "get", 2, 2, TST_NONE, OP_GET )
+#endif
+ _OP_DEF(opexe_4, "quit", 0, 1, TST_NUMBER, OP_QUIT )
+ _OP_DEF(opexe_4, "gc", 0, 0, 0, OP_GC )
+ _OP_DEF(opexe_4, "gc-verbose", 0, 1, TST_NONE, OP_GCVERB )
+ _OP_DEF(opexe_4, "new-segment", 0, 1, TST_NUMBER, OP_NEWSEGMENT )
+ _OP_DEF(opexe_4, "oblist", 0, 0, 0, OP_OBLIST )
+ _OP_DEF(opexe_4, "current-input-port", 0, 0, 0, OP_CURR_INPORT )
+ _OP_DEF(opexe_4, "current-output-port", 0, 0, 0, OP_CURR_OUTPORT )
+ _OP_DEF(opexe_4, "open-input-file", 1, 1, TST_STRING, OP_OPEN_INFILE )
+ _OP_DEF(opexe_4, "open-output-file", 1, 1, TST_STRING, OP_OPEN_OUTFILE )
+ _OP_DEF(opexe_4, "open-input-output-file", 1, 1, TST_STRING, OP_OPEN_INOUTFILE )
+#if USE_STRING_PORTS
+ _OP_DEF(opexe_4, "open-input-string", 1, 1, TST_STRING, OP_OPEN_INSTRING )
+ _OP_DEF(opexe_4, "open-input-output-string", 1, 1, TST_STRING, OP_OPEN_INOUTSTRING )
+ _OP_DEF(opexe_4, "open-output-string", 0, 1, TST_STRING, OP_OPEN_OUTSTRING )
+ _OP_DEF(opexe_4, "get-output-string", 1, 1, TST_OUTPORT, OP_GET_OUTSTRING )
+#endif
+ _OP_DEF(opexe_4, "close-input-port", 1, 1, TST_INPORT, OP_CLOSE_INPORT )
+ _OP_DEF(opexe_4, "close-output-port", 1, 1, TST_OUTPORT, OP_CLOSE_OUTPORT )
+ _OP_DEF(opexe_4, "interaction-environment", 0, 0, 0, OP_INT_ENV )
+ _OP_DEF(opexe_4, "current-environment", 0, 0, 0, OP_CURR_ENV )
+ _OP_DEF(opexe_5, "read", 0, 1, TST_INPORT, OP_READ )
+ _OP_DEF(opexe_5, "read-char", 0, 1, TST_INPORT, OP_READ_CHAR )
+ _OP_DEF(opexe_5, "peek-char", 0, 1, TST_INPORT, OP_PEEK_CHAR )
+ _OP_DEF(opexe_5, "char-ready?", 0, 1, TST_INPORT, OP_CHAR_READY )
+ _OP_DEF(opexe_5, "set-input-port", 1, 1, TST_INPORT, OP_SET_INPORT )
+ _OP_DEF(opexe_5, "set-output-port", 1, 1, TST_OUTPORT, OP_SET_OUTPORT )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDSEXPR )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDLIST )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDDOT )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQUOTE )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTE )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTEVEC )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUNQUOTE )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUQTSP )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDVEC )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P0LIST )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P1LIST )
+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_PVECFROM )
+ _OP_DEF(opexe_6, "length", 1, 1, TST_LIST, OP_LIST_LENGTH )
+ _OP_DEF(opexe_6, "assq", 2, 2, TST_NONE, OP_ASSQ )
+ _OP_DEF(opexe_6, "get-closure-code", 1, 1, TST_NONE, OP_GET_CLOSURE )
+ _OP_DEF(opexe_6, "closure?", 1, 1, TST_NONE, OP_CLOSUREP )
+ _OP_DEF(opexe_6, "macro?", 1, 1, TST_NONE, OP_MACROP )
+#undef _OP_DEF
diff --git a/plug-ins/script-fu/tinyscheme/scheme-private.h b/plug-ins/script-fu/tinyscheme/scheme-private.h
new file mode 100644
index 0000000..89840c2
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/scheme-private.h
@@ -0,0 +1,227 @@
+/* scheme-private.h */
+
+#ifndef _SCHEME_PRIVATE_H
+#define _SCHEME_PRIVATE_H
+
+#include "scheme.h"
+/*------------------ Ugly internals -----------------------------------*/
+/*------------------ Of interest only to FFI users --------------------*/
+
+enum scheme_port_kind {
+ port_free=0,
+ port_file=1,
+ port_string=2,
+ port_srfi6=4,
+ port_input=16,
+ port_output=32,
+ port_saw_EOF=64
+};
+
+typedef struct port {
+ unsigned char kind;
+ union {
+ struct {
+ FILE *file;
+ int closeit;
+#if SHOW_ERROR_LINE
+ int curr_line;
+ char *filename;
+#endif
+ } stdio;
+ struct {
+ char *start;
+ char *past_the_end;
+ char *curr;
+ } string;
+ } rep;
+} port;
+
+/* cell structure */
+struct cell {
+ unsigned int _flag;
+ union {
+ struct {
+ char *_svalue;
+ int _length;
+ } _string;
+ num _number;
+ port *_port;
+ foreign_func _ff;
+ struct {
+ struct cell *_car;
+ struct cell *_cdr;
+ } _cons;
+ } _object;
+};
+
+struct scheme {
+/* arrays for segments */
+func_alloc malloc;
+func_dealloc free;
+
+/* return code */
+int retcode;
+int tracing;
+
+
+#ifndef CELL_SEGSIZE
+#define CELL_SEGSIZE 25000 /* # of cells in one segment */
+#endif
+#ifndef CELL_NSEGMENT
+#define CELL_NSEGMENT 50 /* # of segments for cells */
+#endif
+char *alloc_seg[CELL_NSEGMENT];
+pointer cell_seg[CELL_NSEGMENT];
+int last_cell_seg;
+
+/* We use 5 registers. */
+pointer args; /* register for arguments of function */
+pointer envir; /* stack register for current environment */
+pointer code; /* register for current code */
+pointer dump; /* stack register for next evaluation */
+pointer foreign_error; /* used for foreign functions to signal an error */
+
+int interactive_repl; /* are we in an interactive REPL? */
+int print_output; /* set to 1 to print results and error messages */
+
+struct cell _sink;
+pointer sink; /* when mem. alloc. fails */
+struct cell _NIL;
+pointer NIL; /* special cell representing empty cell */
+struct cell _HASHT;
+pointer T; /* special cell representing #t */
+struct cell _HASHF;
+pointer F; /* special cell representing #f */
+struct cell _EOF_OBJ;
+pointer EOF_OBJ; /* special cell representing end-of-file object */
+pointer oblist; /* pointer to symbol table */
+pointer global_env; /* pointer to global environment */
+
+pointer c_nest; /* stack for nested calls from C */
+
+/* global pointers to special symbols */
+pointer LAMBDA; /* pointer to syntax lambda */
+pointer QUOTE; /* pointer to syntax quote */
+
+pointer QQUOTE; /* pointer to symbol quasiquote */
+pointer UNQUOTE; /* pointer to symbol unquote */
+pointer UNQUOTESP; /* pointer to symbol unquote-splicing */
+pointer FEED_TO; /* => */
+pointer COLON_HOOK; /* *colon-hook* */
+pointer ERROR_HOOK; /* *error-hook* */
+pointer SHARP_HOOK; /* *sharp-hook* */
+pointer COMPILE_HOOK; /* *compile-hook* */
+
+pointer free_cell; /* pointer to top of free cells */
+long fcells; /* # of free cells */
+
+pointer inport;
+pointer outport;
+pointer save_inport;
+pointer loadport;
+
+#ifndef MAXFIL
+#define MAXFIL 64
+#endif
+port load_stack[MAXFIL]; /* Stack of open files for port -1 (LOADing) */
+int nesting_stack[MAXFIL];
+int file_i;
+int nesting;
+
+char gc_verbose; /* if gc_verbose is not zero, print gc status */
+char no_memory; /* Whether mem. alloc. has failed */
+
+#ifndef LINESIZE
+#define LINESIZE 1024
+#endif
+char linebuff[LINESIZE];
+#ifndef STRBUFFSIZE
+#define STRBUFFSIZE 1024
+#endif
+char strbuff[STRBUFFSIZE];
+
+FILE *tmpfp;
+int tok;
+int print_flag;
+pointer value;
+int op;
+
+void *ext_data; /* For the benefit of foreign functions */
+long gensym_cnt;
+
+struct scheme_interface *vptr;
+void *dump_base; /* pointer to base of allocated dump stack */
+int dump_size; /* number of frames allocated for dump stack */
+
+gunichar backchar[2];
+int bc_flag;
+};
+
+/* operator code */
+enum scheme_opcodes {
+#define _OP_DEF(A,B,C,D,E,OP) OP,
+#include "opdefines.h"
+ OP_MAXDEFINED
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define cons(sc,a,b) _cons(sc,a,b,0)
+#define immutable_cons(sc,a,b) _cons(sc,a,b,1)
+
+int is_string(pointer p);
+char *string_value(pointer p);
+int is_number(pointer p);
+num nvalue(pointer p);
+long ivalue(pointer p);
+double rvalue(pointer p);
+int is_integer(pointer p);
+int is_real(pointer p);
+int is_character(pointer p);
+int string_length(pointer p);
+gunichar charvalue(pointer p);
+int is_vector(pointer p);
+
+int is_port(pointer p);
+int is_inport(pointer p);
+int is_outport(pointer p);
+
+int is_pair(pointer p);
+pointer pair_car(pointer p);
+pointer pair_cdr(pointer p);
+pointer set_car(pointer p, pointer q);
+pointer set_cdr(pointer p, pointer q);
+
+int is_symbol(pointer p);
+char *symname(pointer p);
+char *symkey(pointer p);
+int hasprop(pointer p);
+
+int is_syntax(pointer p);
+int is_proc(pointer p);
+int is_foreign(pointer p);
+char *syntaxname(pointer p);
+int is_closure(pointer p);
+int is_macro(pointer p);
+pointer closure_code(pointer p);
+pointer closure_env(pointer p);
+
+int is_continuation(pointer p);
+int is_promise(pointer p);
+int is_environment(pointer p);
+int is_immutable(pointer p);
+void setimmutable(pointer p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/
diff --git a/plug-ins/script-fu/tinyscheme/scheme.c b/plug-ins/script-fu/tinyscheme/scheme.c
new file mode 100644
index 0000000..ff73801
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/scheme.c
@@ -0,0 +1,5352 @@
+/* T I N Y S C H E M E 1 . 4 1
+ * Dimitrios Souflis (dsouflis@acm.org)
+ * Based on MiniScheme (original credits follow)
+ * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
+ * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
+ * (MINISCM) This version has been modified by R.C. Secrist.
+ * (MINISCM)
+ * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
+ * (MINISCM)
+ * (MINISCM) This is a revised and modified version by Akira KIDA.
+ * (MINISCM) current version is 0.85k4 (15 May 1994)
+ *
+ */
+
+/* ******** READ THE FOLLOWING BEFORE MODIFYING THIS FILE! ******** */
+/* This copy of TinyScheme has been modified to support UTF-8 coded */
+/* character strings. As a result, the length of a string in bytes */
+/* may not be the same as the length of a string in characters. You */
+/* must keep this in mind at all times while making any changes to */
+/* the routines in this file and when adding new features. */
+/* */
+/* UTF-8 modifications made by Kevin Cozens (kcozens@interlog.com) */
+/* **************************************************************** */
+
+#include "config.h"
+
+#define _SCHEME_SOURCE
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#if USE_DL
+# include "dynload.h"
+#endif
+#if USE_MATH
+# include <math.h>
+#endif
+
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "../script-fu-intl.h"
+
+#include "scheme-private.h"
+
+#if !STANDALONE
+static ts_output_func ts_output_handler = NULL;
+static gpointer ts_output_data = NULL;
+
+void
+ts_register_output_func (ts_output_func func,
+ gpointer user_data)
+{
+ ts_output_handler = func;
+ ts_output_data = user_data;
+}
+
+/* len is length of 'string' in bytes or -1 for null terminated strings */
+void
+ts_output_string (TsOutputType type,
+ const char *string,
+ int len)
+{
+ if (len < 0)
+ len = strlen (string);
+
+ if (ts_output_handler && len > 0)
+ (* ts_output_handler) (type, string, len, ts_output_data);
+}
+#endif
+
+/* Used for documentation purposes, to signal functions in 'interface' */
+#define INTERFACE
+
+#define TOK_EOF (-1)
+#define TOK_LPAREN 0
+#define TOK_RPAREN 1
+#define TOK_DOT 2
+#define TOK_ATOM 3
+#define TOK_QUOTE 4
+#define TOK_COMMENT 5
+#define TOK_DQUOTE 6
+#define TOK_BQUOTE 7
+#define TOK_COMMA 8
+#define TOK_ATMARK 9
+#define TOK_SHARP 10
+#define TOK_SHARP_CONST 11
+#define TOK_VEC 12
+#define TOK_USCORE 13
+
+#define BACKQUOTE '`'
+#define DELIMITERS "()\";\f\t\v\n\r "
+
+/*
+ * Basic memory allocation units
+ */
+
+#define banner "TinyScheme 1.41 (with UTF-8 support)"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define stricmp utf8_stricmp
+
+static int utf8_stricmp(const char *s1, const char *s2)
+{
+ char *s1a, *s2a;
+ int result;
+
+ s1a = g_utf8_casefold(s1, -1);
+ s2a = g_utf8_casefold(s2, -1);
+
+ result = g_utf8_collate(s1a, s2a);
+
+ g_free(s1a);
+ g_free(s2a);
+ return result;
+}
+
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+
+#if USE_STRLWR
+/*
+#error FIXME: Can't just use g_utf8_strdown since it allocates a new string
+#define strlwr(s) g_utf8_strdown(s, -1)
+*/
+#else
+#define strlwr(s) s
+#endif
+
+#ifndef prompt
+# define prompt "ts> "
+#endif
+
+#ifndef InitFile
+# define InitFile "init.scm"
+#endif
+
+#ifndef FIRST_CELLSEGS
+# define FIRST_CELLSEGS 3
+#endif
+
+enum scheme_types {
+ T_STRING=1,
+ T_NUMBER=2,
+ T_SYMBOL=3,
+ T_PROC=4,
+ T_PAIR=5,
+ T_CLOSURE=6,
+ T_CONTINUATION=7,
+ T_FOREIGN=8,
+ T_CHARACTER=9,
+ T_PORT=10,
+ T_VECTOR=11,
+ T_MACRO=12,
+ T_PROMISE=13,
+ T_ENVIRONMENT=14,
+ T_LAST_SYSTEM_TYPE=14
+};
+
+/* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
+#define ADJ 32
+#define TYPE_BITS 5
+#define T_MASKTYPE 31 /* 0000000000011111 */
+#define T_SYNTAX 4096 /* 0001000000000000 */
+#define T_IMMUTABLE 8192 /* 0010000000000000 */
+#define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
+#define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
+#define MARK 32768 /* 1000000000000000 */
+#define UNMARK 32767 /* 0111111111111111 */
+
+static num num_add(num a, num b);
+static num num_mul(num a, num b);
+static num num_div(num a, num b);
+static num num_intdiv(num a, num b);
+static num num_sub(num a, num b);
+static num num_rem(num a, num b);
+static num num_mod(num a, num b);
+static int num_eq(num a, num b);
+static int num_gt(num a, num b);
+static int num_ge(num a, num b);
+static int num_lt(num a, num b);
+static int num_le(num a, num b);
+
+#if USE_MATH
+static double round_per_R5RS(double x);
+#endif
+static int is_zero_double(double x);
+static INLINE int num_is_integer(pointer p) {
+ return ((p)->_object._number.is_fixnum);
+}
+
+static num num_zero;
+static num num_one;
+
+/* macros for cell operations */
+#define typeflag(p) ((p)->_flag)
+#define type(p) (typeflag(p)&T_MASKTYPE)
+
+INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
+#define strvalue(p) ((p)->_object._string._svalue)
+#define strlength(p) ((p)->_object._string._length)
+
+INTERFACE static int is_list(scheme *sc, pointer a);
+INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
+INTERFACE static void fill_vector(pointer vec, pointer obj);
+INTERFACE static pointer vector_elem(pointer vec, int ielem);
+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
+INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
+INTERFACE INLINE int is_integer(pointer p) {
+ if (!is_number(p))
+ return 0;
+ if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
+ return 1;
+ return 0;
+}
+
+INTERFACE INLINE int is_real(pointer p) {
+ return is_number(p) && (!(p)->_object._number.is_fixnum);
+}
+
+INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
+INTERFACE INLINE int string_length(pointer p) { return strlength(p); }
+INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
+INLINE num nvalue(pointer p) { return ((p)->_object._number); }
+INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
+INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
+#define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
+#define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
+#define set_num_integer(p) (p)->_object._number.is_fixnum=1;
+#define set_num_real(p) (p)->_object._number.is_fixnum=0;
+INTERFACE gunichar charvalue(pointer p) { return (gunichar)ivalue_unchecked(p); }
+
+INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
+INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
+INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
+
+INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
+#define car(p) ((p)->_object._cons._car)
+#define cdr(p) ((p)->_object._cons._cdr)
+INTERFACE pointer pair_car(pointer p) { return car(p); }
+INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
+INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
+INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
+
+INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
+INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
+#if USE_PLIST
+SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); }
+#define symprop(p) cdr(p)
+#endif
+
+INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
+INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
+INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
+INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
+#define procnum(p) ivalue(p)
+static const char *procname(pointer x);
+
+INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
+INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
+INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
+INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
+
+INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
+#define cont_dump(p) cdr(p)
+
+/* To do: promise should be forced ONCE only */
+INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
+
+INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
+#define setenvironment(p) typeflag(p) = T_ENVIRONMENT
+
+#define is_atom(p) (typeflag(p)&T_ATOM)
+#define setatom(p) typeflag(p) |= T_ATOM
+#define clratom(p) typeflag(p) &= CLRATOM
+
+#define is_mark(p) (typeflag(p)&MARK)
+#define setmark(p) typeflag(p) |= MARK
+#define clrmark(p) typeflag(p) &= UNMARK
+
+INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
+/*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
+INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
+
+#define caar(p) car(car(p))
+#define cadr(p) car(cdr(p))
+#define cdar(p) cdr(car(p))
+#define cddr(p) cdr(cdr(p))
+#define cadar(p) car(cdr(car(p)))
+#define caddr(p) car(cdr(cdr(p)))
+#define cdaar(p) cdr(car(car(p)))
+#define cadaar(p) car(cdr(car(car(p))))
+#define cadddr(p) car(cdr(cdr(cdr(p))))
+#define cddddr(p) cdr(cdr(cdr(cdr(p))))
+
+#if USE_CHAR_CLASSIFIERS
+static INLINE int Cisalpha(gunichar c) { return g_unichar_isalpha(c); }
+static INLINE int Cisdigit(gunichar c) { return g_unichar_isdigit(c); }
+static INLINE int Cisspace(gunichar c) { return g_unichar_isspace(c); }
+static INLINE int Cisupper(gunichar c) { return g_unichar_isupper(c); }
+static INLINE int Cislower(gunichar c) { return g_unichar_islower(c); }
+#endif
+
+#if USE_ASCII_NAMES
+static const char *charnames[32]={
+ "nul",
+ "soh",
+ "stx",
+ "etx",
+ "eot",
+ "enq",
+ "ack",
+ "bel",
+ "bs",
+ "ht",
+ "lf",
+ "vt",
+ "ff",
+ "cr",
+ "so",
+ "si",
+ "dle",
+ "dc1",
+ "dc2",
+ "dc3",
+ "dc4",
+ "nak",
+ "syn",
+ "etb",
+ "can",
+ "em",
+ "sub",
+ "esc",
+ "fs",
+ "gs",
+ "rs",
+ "us"
+};
+
+static int is_ascii_name(const char *name, int *pc) {
+ int i;
+ for(i=0; i<32; i++) {
+ if(stricmp(name,charnames[i])==0) {
+ *pc=i;
+ return 1;
+ }
+ }
+ if(stricmp(name,"del")==0) {
+ *pc=127;
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+/* Number of bytes expected AFTER lead byte of UTF-8 character. */
+static const char utf8_length[64] =
+{
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
+ 3,3,3,3,3,3,3,3,4,4,4,4,5,5,0,0 /* 0xf0-0xff */
+};
+
+static int file_push(scheme *sc, const char *fname);
+static void file_pop(scheme *sc);
+static int file_interactive(scheme *sc);
+static INLINE int is_one_of(char *s, gunichar c);
+static int alloc_cellseg(scheme *sc, int n);
+static long binary_decode(const char *s);
+static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
+static pointer _get_cell(scheme *sc, pointer a, pointer b);
+static pointer reserve_cells(scheme *sc, int n);
+static pointer get_consecutive_cells(scheme *sc, int n);
+static pointer find_consecutive_cells(scheme *sc, int n);
+static void finalize_cell(scheme *sc, pointer a);
+static int count_consecutive_cells(pointer x, int needed);
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
+static pointer mk_number(scheme *sc, num n);
+static char *store_string(scheme *sc, int len, const char *str, gunichar fill);
+static pointer mk_vector(scheme *sc, int len);
+static pointer mk_atom(scheme *sc, char *q);
+static pointer mk_sharp_const(scheme *sc, char *name);
+static pointer mk_port(scheme *sc, port *p);
+static pointer port_from_filename(scheme *sc, const char *fn, int prop);
+static pointer port_from_file(scheme *sc, FILE *, int prop);
+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
+static port *port_rep_from_file(scheme *sc, FILE *, int prop);
+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
+static void port_close(scheme *sc, pointer p, int flag);
+static void mark(pointer a);
+static void gc(scheme *sc, pointer a, pointer b);
+static gunichar basic_inchar(port *pt);
+static gunichar inchar(scheme *sc);
+static void backchar(scheme *sc, gunichar c);
+static char *readstr_upto(scheme *sc, char *delim);
+static pointer readstrexp(scheme *sc);
+static INLINE int skipspace(scheme *sc);
+static int token(scheme *sc);
+static void printslashstring(scheme *sc, char *s, int len);
+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
+static void printatom(scheme *sc, pointer l, int f);
+static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
+static pointer mk_closure(scheme *sc, pointer c, pointer e);
+static pointer mk_continuation(scheme *sc, pointer d);
+static pointer reverse(scheme *sc, pointer a);
+static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
+static pointer revappend(scheme *sc, pointer a, pointer b);
+int list_length(scheme *sc, pointer a);
+int eqv(pointer a, pointer b);
+
+static INLINE void dump_stack_mark(scheme *);
+static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
+static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
+static void assign_syntax(scheme *sc, char *name);
+static int syntaxnum(pointer p);
+static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
+scheme *scheme_init_new(void);
+
+#define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
+#define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
+
+static num num_add(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+ ret.value.ivalue= a.value.ivalue+b.value.ivalue;
+ } else {
+ ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_mul(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+ ret.value.ivalue= a.value.ivalue*b.value.ivalue;
+ } else {
+ ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_div(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
+ if(ret.is_fixnum) {
+ ret.value.ivalue= a.value.ivalue/b.value.ivalue;
+ } else {
+ ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_intdiv(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+ ret.value.ivalue= a.value.ivalue/b.value.ivalue;
+ } else {
+ ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_sub(num a, num b) {
+ num ret;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(ret.is_fixnum) {
+ ret.value.ivalue= a.value.ivalue-b.value.ivalue;
+ } else {
+ ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
+ }
+ return ret;
+}
+
+static num num_rem(num a, num b) {
+ num ret;
+ long e1, e2, res;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ e1=num_ivalue(a);
+ e2=num_ivalue(b);
+ res=e1%e2;
+ /* remainder should have same sign as first operand */
+ if (res > 0) {
+ if (e1 < 0) {
+ res -= labs(e2);
+ }
+ } else if (res < 0) {
+ if (e1 > 0) {
+ res += labs(e2);
+ }
+ }
+ ret.value.ivalue=res;
+ return ret;
+}
+
+static num num_mod(num a, num b) {
+ num ret;
+ long e1, e2, res;
+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
+ e1=num_ivalue(a);
+ e2=num_ivalue(b);
+ res=e1%e2;
+ /* modulo should have same sign as second operand */
+ if ((res < 0) != (e2 < 0) && res) { /* if their sign is different... */
+ res+=e2;
+ }
+ ret.value.ivalue=res;
+ return ret;
+}
+
+static int num_eq(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+ ret= a.value.ivalue==b.value.ivalue;
+ } else {
+ ret=num_rvalue(a)==num_rvalue(b);
+ }
+ return ret;
+}
+
+
+static int num_gt(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+ ret= a.value.ivalue>b.value.ivalue;
+ } else {
+ ret=num_rvalue(a)>num_rvalue(b);
+ }
+ return ret;
+}
+
+static int num_ge(num a, num b) {
+ return !num_lt(a,b);
+}
+
+static int num_lt(num a, num b) {
+ int ret;
+ int is_fixnum=a.is_fixnum && b.is_fixnum;
+ if(is_fixnum) {
+ ret= a.value.ivalue<b.value.ivalue;
+ } else {
+ ret=num_rvalue(a)<num_rvalue(b);
+ }
+ return ret;
+}
+
+static int num_le(num a, num b) {
+ return !num_gt(a,b);
+}
+
+#if USE_MATH
+/* Round to nearest. Round to even if midway */
+static double round_per_R5RS(double x) {
+ double fl=floor(x);
+ double ce=ceil(x);
+ double dfl=x-fl;
+ double dce=ce-x;
+ if(dfl>dce) {
+ return ce;
+ } else if(dfl<dce) {
+ return fl;
+ } else {
+ if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
+ return fl;
+ } else {
+ return ce;
+ }
+ }
+}
+#endif
+
+static int is_zero_double(double x) {
+ return x<DBL_MIN && x>-DBL_MIN;
+}
+
+static long binary_decode(const char *s) {
+ long x=0;
+
+ while(*s!=0 && (*s=='1' || *s=='0')) {
+ x<<=1;
+ x+=*s-'0';
+ s++;
+ }
+
+ return x;
+}
+
+/* allocate new cell segment */
+static int alloc_cellseg(scheme *sc, int n) {
+ pointer newp;
+ pointer last;
+ pointer p;
+ char *cp;
+ long i;
+ int k;
+ int adj=ADJ;
+
+ if(adj<sizeof(struct cell)) {
+ adj=sizeof(struct cell);
+ }
+
+ for (k = 0; k < n; k++) {
+ if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
+ return k;
+ cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
+ if (cp == 0)
+ return k;
+ i = ++sc->last_cell_seg ;
+ sc->alloc_seg[i] = cp;
+ /* adjust in TYPE_BITS-bit boundary */
+ if(((uintptr_t)cp)%adj!=0) {
+ cp=(char*)(adj*((uintptr_t)cp/adj+1));
+ }
+ /* insert new segment in address order */
+ newp=(pointer)cp;
+ sc->cell_seg[i] = newp;
+ while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
+ p = sc->cell_seg[i];
+ sc->cell_seg[i] = sc->cell_seg[i - 1];
+ sc->cell_seg[--i] = p;
+ }
+ sc->fcells += CELL_SEGSIZE;
+ last = newp + CELL_SEGSIZE - 1;
+ for (p = newp; p <= last; p++) {
+ typeflag(p) = 0;
+ cdr(p) = p + 1;
+ car(p) = sc->NIL;
+ }
+ /* insert new cells in address order on free list */
+ if (sc->free_cell == sc->NIL || p < sc->free_cell) {
+ cdr(last) = sc->free_cell;
+ sc->free_cell = newp;
+ } else {
+ p = sc->free_cell;
+ while (cdr(p) != sc->NIL && newp > cdr(p))
+ p = cdr(p);
+ cdr(last) = cdr(p);
+ cdr(p) = newp;
+ }
+ }
+ return n;
+}
+
+static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
+ if (sc->free_cell != sc->NIL) {
+ pointer x = sc->free_cell;
+ sc->free_cell = cdr(x);
+ --sc->fcells;
+ return (x);
+ }
+ return _get_cell (sc, a, b);
+}
+
+
+/* get new cell. parameter a, b is marked by gc. */
+static pointer _get_cell(scheme *sc, pointer a, pointer b) {
+ pointer x;
+
+ if(sc->no_memory) {
+ return sc->sink;
+ }
+
+ if (sc->free_cell == sc->NIL) {
+ const int min_to_be_recovered = sc->last_cell_seg*8;
+ gc(sc,a, b);
+ if (sc->fcells < min_to_be_recovered
+ || sc->free_cell == sc->NIL) {
+ /* if only a few recovered, get more to avoid fruitless gc's */
+ if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
+ sc->no_memory=1;
+ return sc->sink;
+ }
+ }
+ }
+ x = sc->free_cell;
+ sc->free_cell = cdr(x);
+ --sc->fcells;
+ return (x);
+}
+
+/* make sure that there is a given number of cells free */
+static pointer reserve_cells(scheme *sc, int n) {
+ if(sc->no_memory) {
+ return sc->NIL;
+ }
+
+ /* Are there enough cells available? */
+ if (sc->fcells < n) {
+ /* If not, try gc'ing some */
+ gc(sc, sc->NIL, sc->NIL);
+ if (sc->fcells < n) {
+ /* If there still aren't, try getting more heap */
+ if (!alloc_cellseg(sc,1)) {
+ sc->no_memory=1;
+ return sc->NIL;
+ }
+ }
+ if (sc->fcells < n) {
+ /* If all fail, report failure */
+ sc->no_memory=1;
+ return sc->NIL;
+ }
+ }
+ return (sc->T);
+}
+
+static pointer get_consecutive_cells(scheme *sc, int n) {
+ pointer x;
+
+ if(sc->no_memory) { return sc->sink; }
+
+ /* Are there any cells available? */
+ x=find_consecutive_cells(sc,n);
+ if (x != sc->NIL) { return x; }
+
+ /* If not, try gc'ing some */
+ gc(sc, sc->NIL, sc->NIL);
+ x=find_consecutive_cells(sc,n);
+ if (x != sc->NIL) { return x; }
+
+ /* If there still aren't, try getting more heap */
+ if (!alloc_cellseg(sc,1))
+ {
+ sc->no_memory=1;
+ return sc->sink;
+ }
+
+ x=find_consecutive_cells(sc,n);
+ if (x != sc->NIL) { return x; }
+
+ /* If all fail, report failure */
+ sc->no_memory=1;
+ return sc->sink;
+}
+
+static int count_consecutive_cells(pointer x, int needed) {
+ int n=1;
+ while(cdr(x)==x+1) {
+ x=cdr(x);
+ n++;
+ if(n>needed) return n;
+ }
+ return n;
+}
+
+static pointer find_consecutive_cells(scheme *sc, int n) {
+ pointer *pp;
+ int cnt;
+
+ pp=&sc->free_cell;
+ while(*pp!=sc->NIL) {
+ cnt=count_consecutive_cells(*pp,n);
+ if(cnt>=n) {
+ pointer x=*pp;
+ *pp=cdr(*pp+n-1);
+ sc->fcells -= n;
+ return x;
+ }
+ pp=&cdr(*pp+cnt-1);
+ }
+ return sc->NIL;
+}
+
+/* To retain recent allocs before interpreter knows about them -
+ Tehom */
+
+static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
+{
+ pointer holder = get_cell_x(sc, recent, extra);
+ typeflag(holder) = T_PAIR | T_IMMUTABLE;
+ car(holder) = recent;
+ cdr(holder) = car(sc->sink);
+ car(sc->sink) = holder;
+}
+
+
+static pointer get_cell(scheme *sc, pointer a, pointer b)
+{
+ pointer cell = get_cell_x(sc, a, b);
+ /* For right now, include "a" and "b" in "cell" so that gc doesn't
+ think they are garbage. */
+ /* Tentatively record it as a pair so gc understands it. */
+ typeflag(cell) = T_PAIR;
+ car(cell) = a;
+ cdr(cell) = b;
+ push_recent_alloc(sc, cell, sc->NIL);
+ return cell;
+}
+
+static pointer get_vector_object(scheme *sc, int len, pointer init)
+{
+ pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
+ if(sc->no_memory) { return sc->sink; }
+ /* Record it as a vector so that gc understands it. */
+ typeflag(cells) = (T_VECTOR | T_ATOM);
+ ivalue_unchecked(cells)=len;
+ set_num_integer(cells);
+ fill_vector(cells,init);
+ push_recent_alloc(sc, cells, sc->NIL);
+ return cells;
+}
+
+static INLINE void ok_to_freely_gc(scheme *sc)
+{
+ car(sc->sink) = sc->NIL;
+}
+
+
+#if defined TSGRIND
+static void check_cell_alloced(pointer p, int expect_alloced)
+{
+ /* Can't use putstr(sc,str) because callers have no access to
+ sc. */
+ if(typeflag(p) & !expect_alloced)
+ {
+ fprintf(stderr,"Cell is already allocated!\n");
+ }
+ if(!(typeflag(p)) & expect_alloced)
+ {
+ fprintf(stderr,"Cell is not allocated!\n");
+ }
+}
+static void check_range_alloced(pointer p, int n, int expect_alloced)
+{
+ int i;
+ for(i = 0;i<n;i++)
+ { (void)check_cell_alloced(p+i,expect_alloced); }
+}
+
+#endif
+
+/* Medium level cell allocation */
+
+/* get new cons cell */
+pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
+ pointer x = get_cell(sc,a, b);
+
+ typeflag(x) = T_PAIR;
+ if(immutable) {
+ setimmutable(x);
+ }
+ car(x) = a;
+ cdr(x) = b;
+ return (x);
+}
+
+/* ========== oblist implementation ========== */
+
+#ifndef USE_OBJECT_LIST
+
+static int hash_fn(const char *key, int table_size);
+
+static pointer oblist_initial_value(scheme *sc)
+{
+ return mk_vector(sc, 461); /* probably should be bigger */
+}
+
+/* returns the new symbol */
+static pointer oblist_add_by_name(scheme *sc, const char *name)
+{
+ pointer x;
+ int location;
+
+ x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
+ typeflag(x) = T_SYMBOL;
+ setimmutable(car(x));
+
+ location = hash_fn(name, ivalue_unchecked(sc->oblist));
+ set_vector_elem(sc->oblist, location,
+ immutable_cons(sc, x, vector_elem(sc->oblist, location)));
+ return x;
+}
+
+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
+{
+ int location;
+ pointer x;
+ char *s;
+
+ location = hash_fn(name, ivalue_unchecked(sc->oblist));
+ for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
+ s = symname(car(x));
+ /* case-insensitive, per R5RS section 2. */
+ if(stricmp(name, s) == 0) {
+ return car(x);
+ }
+ }
+ return sc->NIL;
+}
+
+static pointer oblist_all_symbols(scheme *sc)
+{
+ int i;
+ pointer x;
+ pointer ob_list = sc->NIL;
+
+ for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
+ for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
+ ob_list = cons(sc, x, ob_list);
+ }
+ }
+ return ob_list;
+}
+
+#else
+
+static pointer oblist_initial_value(scheme *sc)
+{
+ return sc->NIL;
+}
+
+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
+{
+ pointer x;
+ char *s;
+
+ for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
+ s = symname(car(x));
+ /* case-insensitive, per R5RS section 2. */
+ if(stricmp(name, s) == 0) {
+ return car(x);
+ }
+ }
+ return sc->NIL;
+}
+
+/* returns the new symbol */
+static pointer oblist_add_by_name(scheme *sc, const char *name)
+{
+ pointer x;
+
+ x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
+ typeflag(x) = T_SYMBOL;
+ setimmutable(car(x));
+ sc->oblist = immutable_cons(sc, x, sc->oblist);
+ return x;
+}
+
+static pointer oblist_all_symbols(scheme *sc)
+{
+ return sc->oblist;
+}
+
+#endif
+
+static pointer mk_port(scheme *sc, port *p) {
+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+ typeflag(x) = T_PORT|T_ATOM;
+ x->_object._port=p;
+ return (x);
+}
+
+pointer mk_foreign_func(scheme *sc, foreign_func f) {
+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_FOREIGN | T_ATOM);
+ x->_object._ff=f;
+ return (x);
+}
+
+INTERFACE pointer mk_character(scheme *sc, gunichar c) {
+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_CHARACTER | T_ATOM);
+ ivalue_unchecked(x)= c;
+ set_num_integer(x);
+ return (x);
+}
+
+/* get number atom (integer) */
+INTERFACE pointer mk_integer(scheme *sc, long num) {
+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_NUMBER | T_ATOM);
+ ivalue_unchecked(x)= num;
+ set_num_integer(x);
+ return (x);
+}
+
+INTERFACE pointer mk_real(scheme *sc, double n) {
+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_NUMBER | T_ATOM);
+ rvalue_unchecked(x)= n;
+ set_num_real(x);
+ return (x);
+}
+
+static pointer mk_number(scheme *sc, num n) {
+ if(n.is_fixnum) {
+ return mk_integer(sc,n.value.ivalue);
+ } else {
+ return mk_real(sc,n.value.rvalue);
+ }
+}
+
+pointer foreign_error (scheme *sc, const char *s, pointer a) {
+ sc->foreign_error = cons (sc, mk_string (sc, s), a);
+ return sc->T;
+}
+
+/* char_cnt is length of string in chars. */
+/* str points to a NUL terminated string. */
+/* Only uses fill_char if str is NULL. */
+/* This routine automatically adds 1 byte */
+/* to allow space for terminating NUL. */
+static char *store_string(scheme *sc, int char_cnt,
+ const char *str, gunichar fill) {
+ int len;
+ int i;
+ gchar utf8[7];
+ gchar *q;
+ gchar *q2;
+
+ if(str!=0) {
+ q2 = g_utf8_offset_to_pointer(str, (long)char_cnt);
+ (void)g_utf8_validate(str, -1, (const gchar **)&q);
+ if (q <= q2)
+ len = q - str;
+ else
+ len = q2 - str;
+ q=(gchar*)sc->malloc(len+1);
+ } else {
+ len = g_unichar_to_utf8(fill, utf8);
+ q=(gchar*)sc->malloc(char_cnt*len+1);
+ }
+
+ if(q==0) {
+ sc->no_memory=1;
+ return sc->strbuff;
+ }
+ if(str!=0) {
+ memcpy(q, str, len);
+ q[len]=0;
+ } else {
+ q2 = q;
+ for (i = 0; i < char_cnt; ++i)
+ {
+ memcpy(q2, utf8, len);
+ q2 += len;
+ }
+ *q2=0;
+ }
+ return (q);
+}
+
+/* get new string */
+INTERFACE pointer mk_string(scheme *sc, const char *str) {
+ return mk_counted_string(sc,str,g_utf8_strlen(str, -1));
+}
+
+/* str points to a NUL terminated string. */
+/* len is the length of str in characters */
+INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_STRING | T_ATOM);
+ strvalue(x) = store_string(sc,len,str,0);
+ strlength(x) = len;
+ return (x);
+}
+
+/* len is the length for the empty string in characters */
+INTERFACE pointer mk_empty_string(scheme *sc, int len, gunichar fill) {
+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
+
+ typeflag(x) = (T_STRING | T_ATOM);
+ strvalue(x) = store_string(sc,len,0,fill);
+ strlength(x) = len;
+ return (x);
+}
+
+INTERFACE static pointer mk_vector(scheme *sc, int len)
+{ return get_vector_object(sc,len,sc->NIL); }
+
+INTERFACE static void fill_vector(pointer vec, pointer obj) {
+ int i;
+ int num=ivalue(vec)/2+ivalue(vec)%2;
+ for(i=0; i<num; i++) {
+ typeflag(vec+1+i) = T_PAIR;
+ setimmutable(vec+1+i);
+ car(vec+1+i)=obj;
+ cdr(vec+1+i)=obj;
+ }
+}
+
+INTERFACE static pointer vector_elem(pointer vec, int ielem) {
+ int n=ielem/2;
+ if(ielem%2==0) {
+ return car(vec+1+n);
+ } else {
+ return cdr(vec+1+n);
+ }
+}
+
+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
+ int n=ielem/2;
+ if(ielem%2==0) {
+ return car(vec+1+n)=a;
+ } else {
+ return cdr(vec+1+n)=a;
+ }
+}
+
+/* get new symbol */
+INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
+ pointer x;
+
+ /* first check oblist */
+ x = oblist_find_by_name(sc, name);
+ if (x != sc->NIL) {
+ return (x);
+ } else {
+ x = oblist_add_by_name(sc, name);
+ return (x);
+ }
+}
+
+INTERFACE pointer gensym(scheme *sc) {
+ pointer x;
+ char name[40];
+
+ for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
+ snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
+
+ /* first check oblist */
+ x = oblist_find_by_name(sc, name);
+
+ if (x != sc->NIL) {
+ continue;
+ } else {
+ x = oblist_add_by_name(sc, name);
+ return (x);
+ }
+ }
+
+ return sc->NIL;
+}
+
+/* make symbol or number atom from string */
+static pointer mk_atom(scheme *sc, char *q) {
+ char c, *p;
+ int has_dec_point=0;
+ int has_fp_exp = 0;
+
+#if USE_COLON_HOOK
+ if((p=strstr(q,"::"))!=0) {
+ *p=0;
+ return cons(sc, sc->COLON_HOOK,
+ cons(sc,
+ cons(sc,
+ sc->QUOTE,
+ cons(sc, mk_atom(sc,p+2), sc->NIL)),
+ cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
+ }
+#endif
+
+ p = q;
+ c = *p++;
+ if ((c == '+') || (c == '-')) {
+ c = *p++;
+ if (c == '.') {
+ has_dec_point=1;
+ c = *p++;
+ }
+ if (!isdigit(c)) {
+ return (mk_symbol(sc, strlwr(q)));
+ }
+ } else if (c == '.') {
+ has_dec_point=1;
+ c = *p++;
+ if (!isdigit(c)) {
+ return (mk_symbol(sc, strlwr(q)));
+ }
+ } else if (!isdigit(c)) {
+ return (mk_symbol(sc, strlwr(q)));
+ }
+
+ for ( ; (c = *p) != 0; ++p) {
+ if (!isdigit(c)) {
+ if(c=='.') {
+ if(!has_dec_point) {
+ has_dec_point=1;
+ continue;
+ }
+ }
+ else if ((c == 'e') || (c == 'E')) {
+ if(!has_fp_exp) {
+ has_dec_point = 1; /* decimal point illegal
+ from now on */
+ p++;
+ if ((*p == '-') || (*p == '+') || isdigit(*p)) {
+ continue;
+ }
+ }
+ }
+ return (mk_symbol(sc, strlwr(q)));
+ }
+ }
+ if(has_dec_point) {
+ return mk_real(sc,g_ascii_strtod(q,NULL));
+ }
+ return (mk_integer(sc, atol(q)));
+}
+
+/* make constant */
+static pointer mk_sharp_const(scheme *sc, char *name) {
+ long x;
+ char tmp[STRBUFFSIZE];
+
+ if (!strcmp(name, "t"))
+ return (sc->T);
+ else if (!strcmp(name, "f"))
+ return (sc->F);
+ else if (*name == 'o') {/* #o (octal) */
+ snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
+ sscanf(tmp, "%lo", (long unsigned *)&x);
+ return (mk_integer(sc, x));
+ } else if (*name == 'd') { /* #d (decimal) */
+ sscanf(name+1, "%ld", (long int *)&x);
+ return (mk_integer(sc, x));
+ } else if (*name == 'x') { /* #x (hex) */
+ snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
+ sscanf(tmp, "%lx", (long unsigned *)&x);
+ return (mk_integer(sc, x));
+ } else if (*name == 'b') { /* #b (binary) */
+ x = binary_decode(name+1);
+ return (mk_integer(sc, x));
+ } else if (*name == '\\') { /* #\w (character) */
+ gunichar c=0;
+ if(stricmp(name+1,"space")==0) {
+ c=' ';
+ } else if(stricmp(name+1,"newline")==0) {
+ c='\n';
+ } else if(stricmp(name+1,"return")==0) {
+ c='\r';
+ } else if(stricmp(name+1,"tab")==0) {
+ c='\t';
+ } else if(name[1]=='x' && name[2]!=0) {
+ int c1=0;
+ if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
+ c=c1;
+ } else {
+ return sc->NIL;
+ }
+#if USE_ASCII_NAMES
+ } else if(is_ascii_name(name+1,&c)) {
+ /* nothing */
+#endif
+ } else if(name[2]==0) {
+ c=name[1];
+ } else {
+ return sc->NIL;
+ }
+ return mk_character(sc,c);
+ } else
+ return (sc->NIL);
+}
+
+/* ========== garbage collector ========== */
+
+/*--
+ * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
+ * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
+ * for marking.
+ */
+static void mark(pointer a) {
+ pointer t, q, p;
+
+ t = (pointer) 0;
+ p = a;
+E2: setmark(p);
+ if(is_vector(p)) {
+ int i;
+ int num=ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
+ for(i=0; i<num; i++) {
+ /* Vector cells will be treated like ordinary cells */
+ mark(p+1+i);
+ }
+ }
+ if (is_atom(p))
+ goto E6;
+ /* E4: down car */
+ q = car(p);
+ if (q && !is_mark(q)) {
+ setatom(p); /* a note that we have moved car */
+ car(p) = t;
+ t = p;
+ p = q;
+ goto E2;
+ }
+ E5: q = cdr(p); /* down cdr */
+ if (q && !is_mark(q)) {
+ cdr(p) = t;
+ t = p;
+ p = q;
+ goto E2;
+ }
+E6: /* up. Undo the link switching from steps E4 and E5. */
+ if (!t)
+ return;
+ q = t;
+ if (is_atom(q)) {
+ clratom(q);
+ t = car(q);
+ car(q) = p;
+ p = q;
+ goto E5;
+ } else {
+ t = cdr(q);
+ cdr(q) = p;
+ p = q;
+ goto E6;
+ }
+}
+
+/* garbage collection. parameter a, b is marked. */
+static void gc(scheme *sc, pointer a, pointer b) {
+ pointer p;
+ int i;
+
+ if(sc->gc_verbose) {
+ putstr(sc, "gc...");
+ }
+
+ /* mark system globals */
+ mark(sc->oblist);
+ mark(sc->global_env);
+
+ /* mark current registers */
+ mark(sc->args);
+ mark(sc->envir);
+ mark(sc->code);
+ dump_stack_mark(sc);
+ mark(sc->value);
+ mark(sc->inport);
+ mark(sc->save_inport);
+ mark(sc->outport);
+ mark(sc->loadport);
+
+ /* Mark recent objects the interpreter doesn't know about yet. */
+ mark(car(sc->sink));
+ /* Mark any older stuff above nested C calls */
+ mark(sc->c_nest);
+
+ /* mark variables a, b */
+ mark(a);
+ mark(b);
+
+ /* garbage collect */
+ clrmark(sc->NIL);
+ sc->fcells = 0;
+ sc->free_cell = sc->NIL;
+ /* free-list is kept sorted by address so as to maintain consecutive
+ ranges, if possible, for use with vectors. Here we scan the cells
+ (which are also kept sorted by address) downwards to build the
+ free-list in sorted order.
+ */
+ for (i = sc->last_cell_seg; i >= 0; i--) {
+ p = sc->cell_seg[i] + CELL_SEGSIZE;
+ while (--p >= sc->cell_seg[i]) {
+ if (is_mark(p)) {
+ clrmark(p);
+ } else {
+ /* reclaim cell */
+ if (typeflag(p) != 0) {
+ finalize_cell(sc, p);
+ typeflag(p) = 0;
+ car(p) = sc->NIL;
+ }
+ ++sc->fcells;
+ cdr(p) = sc->free_cell;
+ sc->free_cell = p;
+ }
+ }
+ }
+
+ if (sc->gc_verbose) {
+ char msg[80];
+ snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
+ putstr(sc,msg);
+ }
+}
+
+static void finalize_cell(scheme *sc, pointer a) {
+ if(is_string(a)) {
+ sc->free(strvalue(a));
+ } else if(is_port(a)) {
+ if(a->_object._port->kind&port_file
+ && a->_object._port->rep.stdio.closeit) {
+ port_close(sc,a,port_input|port_output);
+ }
+ sc->free(a->_object._port);
+ }
+}
+
+/* ========== Routines for Reading ========== */
+
+static int file_push(scheme *sc, const char *fname) {
+ FILE *fin = NULL;
+ if (sc->file_i == MAXFIL-1)
+ return 0;
+
+ fin=g_fopen(fname,"rb");
+ if(fin!=0) {
+ sc->file_i++;
+ sc->load_stack[sc->file_i].kind=port_file|port_input;
+ sc->load_stack[sc->file_i].rep.stdio.file=fin;
+ sc->load_stack[sc->file_i].rep.stdio.closeit=1;
+ sc->nesting_stack[sc->file_i]=0;
+ sc->loadport->_object._port=sc->load_stack+sc->file_i;
+
+#if SHOW_ERROR_LINE
+ sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
+ if(fname)
+ sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
+#endif
+ }
+ return fin!=0;
+}
+
+static void file_pop(scheme *sc) {
+ if(sc->file_i != 0) {
+ sc->nesting=sc->nesting_stack[sc->file_i];
+ port_close(sc,sc->loadport,port_input);
+ sc->file_i--;
+ sc->loadport->_object._port=sc->load_stack+sc->file_i;
+ }
+}
+
+static int file_interactive(scheme *sc) {
+ return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
+ && sc->inport->_object._port->kind&port_file;
+}
+
+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
+ FILE *f;
+ char *rw;
+ port *pt;
+ if(prop==(port_input|port_output)) {
+ rw="a+b";
+ } else if(prop==port_output) {
+ rw="wb";
+ } else {
+ rw="rb";
+ }
+ f=g_fopen(fn,rw);
+ if(f==0) {
+ return 0;
+ }
+ pt=port_rep_from_file(sc,f,prop);
+ pt->rep.stdio.closeit=1;
+
+#if SHOW_ERROR_LINE
+ if(fn)
+ pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
+
+ pt->rep.stdio.curr_line = 0;
+#endif
+ return pt;
+}
+
+static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
+ port *pt;
+ pt=port_rep_from_filename(sc,fn,prop);
+ if(pt==0) {
+ return sc->NIL;
+ }
+ return mk_port(sc,pt);
+}
+
+static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
+{
+ port *pt;
+
+ pt = (port *)sc->malloc(sizeof *pt);
+ if (pt == NULL) {
+ return NULL;
+ }
+ pt->kind = port_file | prop;
+ pt->rep.stdio.file = f;
+ pt->rep.stdio.closeit = 0;
+ return pt;
+}
+
+static pointer port_from_file(scheme *sc, FILE *f, int prop) {
+ port *pt;
+ pt=port_rep_from_file(sc,f,prop);
+ if(pt==0) {
+ return sc->NIL;
+ }
+ return mk_port(sc,pt);
+}
+
+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
+ port *pt;
+ pt=(port*)sc->malloc(sizeof(port));
+ if(pt==0) {
+ return 0;
+ }
+ pt->kind=port_string|prop;
+ pt->rep.string.start=start;
+ pt->rep.string.curr=start;
+ pt->rep.string.past_the_end=past_the_end;
+ return pt;
+}
+
+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
+ port *pt;
+ pt=port_rep_from_string(sc,start,past_the_end,prop);
+ if(pt==0) {
+ return sc->NIL;
+ }
+ return mk_port(sc,pt);
+}
+
+#define BLOCK_SIZE 256
+
+static port *port_rep_from_scratch(scheme *sc) {
+ port *pt;
+ char *start;
+ pt=(port*)sc->malloc(sizeof(port));
+ if(pt==0) {
+ return 0;
+ }
+ start=sc->malloc(BLOCK_SIZE);
+ if(start==0) {
+ return 0;
+ }
+ memset(start,' ',BLOCK_SIZE-1);
+ start[BLOCK_SIZE-1]='\0';
+ pt->kind=port_string|port_output|port_srfi6;
+ pt->rep.string.start=start;
+ pt->rep.string.curr=start;
+ pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
+ return pt;
+}
+
+static pointer port_from_scratch(scheme *sc) {
+ port *pt;
+ pt=port_rep_from_scratch(sc);
+ if(pt==0) {
+ return sc->NIL;
+ }
+ return mk_port(sc,pt);
+}
+
+static void port_close(scheme *sc, pointer p, int flag) {
+ port *pt=p->_object._port;
+ pt->kind&=~flag;
+ if((pt->kind & (port_input|port_output))==0) {
+ if(pt->kind&port_file) {
+
+#if SHOW_ERROR_LINE
+ /* Cleanup is here so (close-*-port) functions could work too */
+ pt->rep.stdio.curr_line = 0;
+
+ if(pt->rep.stdio.filename)
+ sc->free(pt->rep.stdio.filename);
+#endif
+
+ fclose(pt->rep.stdio.file);
+ }
+ pt->kind=port_free;
+ }
+}
+
+/* This routine will ignore byte sequences that are not valid UTF-8 */
+static gunichar basic_inchar(port *pt) {
+ if(pt->kind & port_file) {
+ int c;
+
+ c = fgetc(pt->rep.stdio.file);
+
+ while (TRUE)
+ {
+ if (c == EOF) return EOF;
+
+ if (c <= 0x7f)
+ return (gunichar) c;
+
+ /* Is this byte an invalid lead per RFC-3629? */
+ if (c < 0xc2 || c > 0xf4)
+ {
+ /* Ignore invalid lead byte and get the next character */
+ c = fgetc(pt->rep.stdio.file);
+ }
+ else /* Byte is valid lead */
+ {
+ unsigned char utf8[7];
+ int len;
+ int i;
+
+ utf8[0] = c; /* Save the lead byte */
+
+ len = utf8_length[c & 0x3F];
+ for (i = 1; i <= len; i++)
+ {
+ c = fgetc(pt->rep.stdio.file);
+
+ /* Stop reading if this is not a continuation character */
+ if ((c & 0xc0) != 0x80)
+ break;
+
+ utf8[i] = c;
+ }
+
+ if (i > len) /* Read the expected number of bytes? */
+ {
+ return g_utf8_get_char_validated ((char *) utf8,
+ sizeof(utf8));
+ }
+
+ /* Not enough continuation characters so ignore and restart */
+ }
+ } /* end of while (TRUE) */
+ } else {
+ gunichar c;
+ int len;
+
+ while (TRUE)
+ {
+ /* Found NUL or at end of input buffer? */
+ if (*pt->rep.string.curr == 0 ||
+ pt->rep.string.curr == pt->rep.string.past_the_end) {
+ return EOF;
+ }
+
+ len = pt->rep.string.past_the_end - pt->rep.string.curr;
+ c = g_utf8_get_char_validated(pt->rep.string.curr, len);
+
+ if (c != (gunichar) -1 &&
+ c != (gunichar) -2) /* Valid UTF-8 character? */
+ {
+ len = g_unichar_to_utf8(c, NULL); /* Length of UTF-8 sequence */
+ pt->rep.string.curr += len;
+ return c;
+ }
+
+ /* Look for next valid UTF-8 character in buffer */
+ pt->rep.string.curr = g_utf8_find_next_char(pt->rep.string.curr,
+ pt->rep.string.past_the_end);
+ } /* end of while (TRUE) */
+ }
+}
+
+/* get new character from input file */
+static gunichar inchar(scheme *sc) {
+ gunichar c;
+ port *pt;
+
+ pt = sc->inport->_object._port;
+ if(pt->kind & port_saw_EOF)
+ { return(EOF); }
+ if(pt->kind&port_file)
+ {
+ if (sc->bc_flag)
+ c = sc->backchar[--sc->bc_flag];
+ else
+ c = basic_inchar(pt);
+ }
+ else
+ c = basic_inchar(pt);
+ if(c == EOF && sc->inport == sc->loadport) {
+ /* Instead, set port_saw_EOF */
+ pt->kind |= port_saw_EOF;
+
+ /* file_pop(sc); */
+ return EOF;
+ /* NOTREACHED */
+ }
+ return c;
+}
+
+/* back character to input buffer */
+static void backchar(scheme *sc, gunichar c) {
+ port *pt;
+ gint charlen;
+
+ if(c==EOF) return;
+ charlen = g_unichar_to_utf8(c, NULL);
+ pt=sc->inport->_object._port;
+ if(pt->kind&port_file) {
+ if (sc->bc_flag < 2)
+ sc->backchar[sc->bc_flag++] = c;
+ } else {
+ if(pt->rep.string.curr!=pt->rep.string.start) {
+ if(pt->rep.string.curr-pt->rep.string.start >= charlen)
+ pt->rep.string.curr -= charlen;
+ else
+ pt->rep.string.curr = pt->rep.string.start;
+ }
+ }
+}
+
+static int realloc_port_string(scheme *sc, port *p)
+{
+ char *start=p->rep.string.start;
+ size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
+ char *str=sc->malloc(new_size);
+ if(str) {
+ memset(str,' ',new_size-1);
+ str[new_size-1]='\0';
+ strcpy(str,start);
+ p->rep.string.start=str;
+ p->rep.string.past_the_end=str+new_size-1;
+ p->rep.string.curr-=start-str;
+ sc->free(start);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* len is number of UTF-8 characters in string pointed to by chars */
+static void putchars(scheme *sc, const char *chars, int char_cnt) {
+ int free_bytes; /* Space remaining in buffer (in bytes) */
+ int l;
+ port *pt=sc->outport->_object._port;
+
+ if (char_cnt <= 0)
+ return;
+
+ /* Get length of 'chars' in bytes */
+ char_cnt = g_utf8_offset_to_pointer(chars, (long)char_cnt) - chars;
+
+ if(pt->kind&port_file) {
+#if STANDALONE
+ fwrite(chars,1,char_cnt,pt->rep.stdio.file);
+ fflush(pt->rep.stdio.file);
+#else
+ /* If output is still directed to stdout (the default) it should be */
+ /* safe to redirect it to the registered output routine. */
+ if (pt->rep.stdio.file == stdout)
+ ts_output_string (TS_OUTPUT_NORMAL, chars, char_cnt);
+ else {
+ fwrite(chars,1,char_cnt,pt->rep.stdio.file);
+ fflush(pt->rep.stdio.file);
+ }
+#endif
+ } else {
+ if (pt->rep.string.past_the_end != pt->rep.string.curr)
+ {
+ free_bytes = pt->rep.string.past_the_end - pt->rep.string.curr;
+ l = min(char_cnt, free_bytes);
+ memcpy(pt->rep.string.curr, chars, l);
+ pt->rep.string.curr += l;
+ }
+ else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt))
+ {
+ free_bytes = pt->rep.string.past_the_end - pt->rep.string.curr;
+ l = min(char_cnt, free_bytes);
+ memcpy(pt->rep.string.curr, chars, char_cnt);
+ pt->rep.string.curr += l;
+ }
+ }
+}
+
+INTERFACE void putcharacter(scheme *sc, gunichar c) {
+ char utf8[7];
+
+ (void)g_unichar_to_utf8(c, utf8);
+ putchars(sc, utf8, 1);
+}
+
+INTERFACE void putstr(scheme *sc, const char *s) {
+ putchars(sc, s, g_utf8_strlen(s, -1));
+}
+
+/* read characters up to delimiter, but cater to character constants */
+static char *readstr_upto(scheme *sc, char *delim) {
+ char *p = sc->strbuff;
+ gunichar c = 0;
+ gunichar c_prev = 0;
+ int len = 0;
+
+ do {
+ c_prev = c;
+ c = inchar(sc);
+ len = g_unichar_to_utf8(c, p);
+ p += len;
+ } while ((p - sc->strbuff < sizeof(sc->strbuff)) &&
+ (c && !is_one_of(delim, c)));
+
+ if(p == sc->strbuff+2 && c_prev == '\\')
+ *p = '\0';
+ else
+ {
+ backchar(sc,c); /* put back the delimiter */
+ p[-len] = '\0';
+ }
+ return sc->strbuff;
+}
+
+/* read string expression "xxx...xxx" */
+static pointer readstrexp(scheme *sc) {
+ char *p = sc->strbuff;
+ gunichar c;
+ int c1=0;
+ int len;
+ enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
+
+ for (;;) {
+ c=inchar(sc);
+ if(c == EOF || p-sc->strbuff > sizeof(sc->strbuff)-1) {
+ return sc->F;
+ }
+ switch(state) {
+ case st_ok:
+ switch(c) {
+ case '\\':
+ state=st_bsl;
+ break;
+ case '"':
+ *p=0;
+ return mk_counted_string(sc,sc->strbuff,
+ g_utf8_strlen(sc->strbuff, sizeof(sc->strbuff)));
+ default:
+ len = g_unichar_to_utf8(c, p);
+ p += len;
+ break;
+ }
+ break;
+ case st_bsl:
+ switch(c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ state=st_oct1;
+ c1=g_unichar_digit_value(c);
+ break;
+ case 'x':
+ case 'X':
+ state=st_x1;
+ c1=0;
+ break;
+ case 'n':
+ *p++='\n';
+ state=st_ok;
+ break;
+ case 't':
+ *p++='\t';
+ state=st_ok;
+ break;
+ case 'r':
+ *p++='\r';
+ state=st_ok;
+ break;
+ case '"':
+ *p++='"';
+ state=st_ok;
+ break;
+ default:
+ len = g_unichar_to_utf8(c, p);
+ p += len;
+ state=st_ok;
+ break;
+ }
+ break;
+ case st_x1:
+ case st_x2:
+ if (!g_unichar_isxdigit(c))
+ return sc->F;
+ c1=(c1<<4)+g_unichar_xdigit_value(c);
+ if(state==st_x1)
+ state=st_x2;
+ else {
+ *p++=c1;
+ state=st_ok;
+ }
+ break;
+ case st_oct1: /* State when handling second octal digit */
+ case st_oct2: /* State when handling third octal digit */
+ if (!g_unichar_isdigit(c) || g_unichar_digit_value(c) > 7)
+ {
+ *p++=c1;
+ backchar(sc, c);
+ state=st_ok;
+ }
+ else
+ {
+ /* Is value of three character octal too big for a byte? */
+ if (state==st_oct2 && c1 >= 32)
+ return sc->F;
+
+ c1=(c1<<3)+g_unichar_digit_value(c);
+
+ if (state == st_oct1)
+ state=st_oct2;
+ else
+ {
+ *p++=c1;
+ state=st_ok;
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* check c is in chars */
+static INLINE int is_one_of(char *s, gunichar c) {
+ if (c==EOF)
+ return 1;
+
+ if (g_utf8_strchr(s, -1, c) != NULL)
+ return (1);
+
+ return (0);
+}
+
+/* skip white characters */
+static INLINE int skipspace(scheme *sc) {
+ gunichar c;
+ int curr_line = 0;
+ do {
+ c=inchar(sc);
+#if SHOW_ERROR_LINE
+ if(c=='\n')
+ curr_line++;
+#endif
+ } while (g_unichar_isspace(c));
+
+/* record it */
+#if SHOW_ERROR_LINE
+ if (sc->load_stack[sc->file_i].kind & port_file)
+ sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
+#endif
+
+ if(c!=EOF) {
+ backchar(sc,c);
+ return 1;
+ }
+ else
+ { return EOF; }
+}
+
+/* get token */
+static int token(scheme *sc) {
+ gunichar c;
+ c = skipspace(sc);
+ if(c == EOF) { return (TOK_EOF); }
+ switch (c=inchar(sc)) {
+ case EOF:
+ return (TOK_EOF);
+ case '(':
+ return (TOK_LPAREN);
+ case ')':
+ return (TOK_RPAREN);
+ case '.':
+ c=inchar(sc);
+ if(is_one_of(" \n\t",c)) {
+ return (TOK_DOT);
+ } else {
+ backchar(sc,c);
+ backchar(sc,'.');
+ return TOK_ATOM;
+ }
+ case '\'':
+ return (TOK_QUOTE);
+ case ';':
+ while ((c=inchar(sc)) != '\n' && c!=EOF)
+ ;
+
+#if SHOW_ERROR_LINE
+ if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+
+ if(c == EOF)
+ { return (TOK_EOF); }
+ else
+ { return (token(sc));}
+ case '"':
+ return (TOK_DQUOTE);
+ case '_':
+ if ((c=inchar(sc)) == '"')
+ return (TOK_USCORE);
+ backchar(sc,c);
+ return (TOK_ATOM);
+ case BACKQUOTE:
+ return (TOK_BQUOTE);
+ case ',':
+ if ((c=inchar(sc)) == '@') {
+ return (TOK_ATMARK);
+ } else {
+ backchar(sc,c);
+ return (TOK_COMMA);
+ }
+ case '#':
+ c=inchar(sc);
+ if (c == '(') {
+ return (TOK_VEC);
+ } else if(c == '!') {
+ while ((c=inchar(sc)) != '\n' && c!=EOF)
+ ;
+
+#if SHOW_ERROR_LINE
+ if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+
+ if(c == EOF)
+ { return (TOK_EOF); }
+ else
+ { return (token(sc));}
+ } else {
+ backchar(sc,c);
+ if(is_one_of(" tfodxb\\",c)) {
+ return TOK_SHARP_CONST;
+ } else {
+ return (TOK_SHARP);
+ }
+ }
+ default:
+ backchar(sc,c);
+ return (TOK_ATOM);
+ }
+}
+
+/* ========== Routines for Printing ========== */
+#define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
+
+static void printslashstring(scheme *sc, char *p, int len) {
+ int i;
+ gunichar c;
+ char *s=(char*)p;
+
+ putcharacter(sc,'"');
+ for (i=0; i<len; i++) {
+ c = g_utf8_get_char(s);
+ /* Is a check for a value of 0xff still valid in UTF8?? ~~~~~ */
+ if(c==0xff || c=='"' || c<' ' || c=='\\') {
+ putcharacter(sc,'\\');
+ switch(c) {
+ case '"':
+ putcharacter(sc,'"');
+ break;
+ case '\n':
+ putcharacter(sc,'n');
+ break;
+ case '\t':
+ putcharacter(sc,'t');
+ break;
+ case '\r':
+ putcharacter(sc,'r');
+ break;
+ case '\\':
+ putcharacter(sc,'\\');
+ break;
+ default: {
+ /* This still needs work ~~~~~ */
+ int d=c/16;
+ putcharacter(sc,'x');
+ if(d<10) {
+ putcharacter(sc,d+'0');
+ } else {
+ putcharacter(sc,d-10+'A');
+ }
+ d=c%16;
+ if(d<10) {
+ putcharacter(sc,d+'0');
+ } else {
+ putcharacter(sc,d-10+'A');
+ }
+ }
+ }
+ } else {
+ putcharacter(sc,c);
+ }
+ s = g_utf8_next_char(s);
+ }
+ putcharacter(sc,'"');
+}
+
+
+/* print atoms */
+static void printatom(scheme *sc, pointer l, int f) {
+ char *p;
+ int len;
+ atom2str(sc,l,f,&p,&len);
+ putchars(sc,p,len);
+}
+
+
+/* Uses internal buffer unless string pointer is already available */
+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
+ char *p;
+
+ if (l == sc->NIL) {
+ p = "()";
+ } else if (l == sc->T) {
+ p = "#t";
+ } else if (l == sc->F) {
+ p = "#f";
+ } else if (l == sc->EOF_OBJ) {
+ p = "#<EOF>";
+ } else if (is_port(l)) {
+ p = "#<PORT>";
+ } else if (is_number(l)) {
+ p = sc->strbuff;
+ if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
+ if(num_is_integer(l)) {
+ snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
+ } else {
+ snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
+ /* r5rs says there must be a '.' (unless 'e'?) */
+ f = strcspn(p, ".e");
+ if (p[f] == 0) {
+ p[f] = '.'; /* not found, so add '.0' at the end */
+ p[f+1] = '0';
+ p[f+2] = 0;
+ }
+ }
+ } else {
+ long v = ivalue(l);
+ if (f == 16) {
+ if (v >= 0)
+ snprintf(p, STRBUFFSIZE, "%lx", v);
+ else
+ snprintf(p, STRBUFFSIZE, "-%lx", -v);
+ } else if (f == 8) {
+ if (v >= 0)
+ snprintf(p, STRBUFFSIZE, "%lo", v);
+ else
+ snprintf(p, STRBUFFSIZE, "-%lo", -v);
+ } else if (f == 2) {
+ unsigned long b = (v < 0) ? -v : v;
+ p = &p[STRBUFFSIZE-1];
+ *p = 0;
+ do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
+ if (v < 0) *--p = '-';
+ }
+ }
+ } else if (is_string(l)) {
+ if (!f) {
+ p = strvalue(l);
+ } else { /* Hack, uses the fact that printing is needed */
+ *pp=sc->strbuff;
+ *plen=0;
+ printslashstring(sc, strvalue(l),
+ g_utf8_strlen(strvalue(l), -1));
+ return;
+ }
+ } else if (is_character(l)) {
+ gunichar c=charvalue(l);
+ p = sc->strbuff;
+ if (!f) {
+ int len = g_unichar_to_utf8(c, p);
+ p[len]=0;
+ } else {
+ switch(c) {
+ case ' ':
+ p = "#\\space";
+ break;
+ case '\n':
+ p = "#\\newline";
+ break;
+ case '\r':
+ p = "#\\return";
+ break;
+ case '\t':
+ p = "#\\tab";
+ break;
+ default:
+#if USE_ASCII_NAMES
+ if(c==127) {
+ p = "#\\del";
+ break;
+ } else if(c<32) {
+ snprintf(p,STRBUFFSIZE, "#\\%s", charnames[c]);
+ break;
+ }
+#else
+ if(c<32) {
+ snprintf(p,STRBUFFSIZE,"#\\x%x",c);
+ break;
+ }
+#endif
+ snprintf(p,STRBUFFSIZE,"#\\%c",c);
+ break;
+ }
+ }
+ } else if (is_symbol(l)) {
+ p = symname(l);
+ } else if (is_proc(l)) {
+ p = sc->strbuff;
+ snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>",
+ procname(l),procnum(l));
+ } else if (is_macro(l)) {
+ p = "#<MACRO>";
+ } else if (is_closure(l)) {
+ p = "#<CLOSURE>";
+ } else if (is_promise(l)) {
+ p = "#<PROMISE>";
+ } else if (is_foreign(l)) {
+ p = sc->strbuff;
+ snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
+ } else if (is_continuation(l)) {
+ p = "#<CONTINUATION>";
+ } else {
+ p = "#<ERROR>";
+ }
+ *pp=p;
+ *plen=g_utf8_strlen(p, -1);
+}
+/* ========== Routines for Evaluation Cycle ========== */
+
+/* make closure. c is code. e is environment */
+static pointer mk_closure(scheme *sc, pointer c, pointer e) {
+ pointer x = get_cell(sc, c, e);
+
+ typeflag(x) = T_CLOSURE;
+ car(x) = c;
+ cdr(x) = e;
+ return (x);
+}
+
+/* make continuation. */
+static pointer mk_continuation(scheme *sc, pointer d) {
+ pointer x = get_cell(sc, sc->NIL, d);
+
+ typeflag(x) = T_CONTINUATION;
+ cont_dump(x) = d;
+ return (x);
+}
+
+static pointer list_star(scheme *sc, pointer d) {
+ pointer p, q;
+ if(cdr(d)==sc->NIL) {
+ return car(d);
+ }
+ p=cons(sc,car(d),cdr(d));
+ q=p;
+ while(cdr(cdr(p))!=sc->NIL) {
+ d=cons(sc,car(p),cdr(p));
+ if(cdr(cdr(p))!=sc->NIL) {
+ p=cdr(d);
+ }
+ }
+ cdr(p)=car(cdr(p));
+ return q;
+}
+
+/* reverse list -- produce new list */
+static pointer reverse(scheme *sc, pointer a) {
+/* a must be checked by gc */
+ pointer p = sc->NIL;
+
+ for ( ; is_pair(a); a = cdr(a)) {
+ p = cons(sc, car(a), p);
+ }
+ return (p);
+}
+
+/* reverse list --- in-place */
+static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
+ pointer p = list, result = term, q;
+
+ while (p != sc->NIL) {
+ q = cdr(p);
+ cdr(p) = result;
+ result = p;
+ p = q;
+ }
+ return (result);
+}
+
+/* append list -- produce new list */
+static pointer revappend(scheme *sc, pointer a, pointer b) {
+ pointer result = a;
+ pointer p = b;
+
+ while (is_pair(p)) {
+ result = cons(sc, car(p), result);
+ p = cdr(p);
+ }
+
+ if (p == sc->NIL) {
+ return result;
+ }
+
+ return sc->F; /* signal an error */
+}
+
+/* equivalence of atoms */
+int eqv(pointer a, pointer b) {
+ if (is_string(a)) {
+ if (is_string(b))
+ return (strvalue(a) == strvalue(b));
+ else
+ return (0);
+ } else if (is_number(a)) {
+ if (is_number(b)) {
+ if (num_is_integer(a) == num_is_integer(b))
+ return num_eq(nvalue(a),nvalue(b));
+ }
+ return (0);
+ } else if (is_character(a)) {
+ if (is_character(b))
+ return charvalue(a)==charvalue(b);
+ else
+ return (0);
+ } else if (is_port(a)) {
+ if (is_port(b))
+ return a==b;
+ else
+ return (0);
+ } else if (is_proc(a)) {
+ if (is_proc(b))
+ return procnum(a)==procnum(b);
+ else
+ return (0);
+ } else {
+ return (a == b);
+ }
+}
+
+/* true or false value macro */
+/* () is #t in R5RS */
+#define is_true(p) ((p) != sc->F)
+#define is_false(p) ((p) == sc->F)
+
+/* ========== Environment implementation ========== */
+
+#if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
+
+static int hash_fn(const char *key, int table_size)
+{
+ unsigned int hashed = 0;
+ const char *c;
+ int bits_per_int = sizeof(unsigned int)*8;
+
+ for (c = key; *c; c++) {
+ /* letters have about 5 bits in them */
+ hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
+ hashed ^= *c;
+ }
+ return hashed % table_size;
+}
+#endif
+
+#ifndef USE_ALIST_ENV
+
+/*
+ * In this implementation, each frame of the environment may be
+ * a hash table: a vector of alists hashed by variable name.
+ * In practice, we use a vector only for the initial frame;
+ * subsequent frames are too small and transient for the lookup
+ * speed to out-weigh the cost of making a new vector.
+ */
+
+static void new_frame_in_env(scheme *sc, pointer old_env)
+{
+ pointer new_frame;
+
+ /* The interaction-environment has about 300 variables in it. */
+ if (old_env == sc->NIL) {
+ new_frame = mk_vector(sc, 461);
+ } else {
+ new_frame = sc->NIL;
+ }
+
+ sc->envir = immutable_cons(sc, new_frame, old_env);
+ setenvironment(sc->envir);
+}
+
+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
+ pointer variable, pointer value)
+{
+ pointer slot = immutable_cons(sc, variable, value);
+
+ if (is_vector(car(env))) {
+ int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
+
+ set_vector_elem(car(env), location,
+ immutable_cons(sc, slot, vector_elem(car(env), location)));
+ } else {
+ car(env) = immutable_cons(sc, slot, car(env));
+ }
+}
+
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
+{
+ pointer x,y;
+ int location;
+
+ for (x = env; x != sc->NIL; x = cdr(x)) {
+ if (is_vector(car(x))) {
+ location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
+ y = vector_elem(car(x), location);
+ } else {
+ y = car(x);
+ }
+ for ( ; y != sc->NIL; y = cdr(y)) {
+ if (caar(y) == hdl) {
+ break;
+ }
+ }
+ if (y != sc->NIL) {
+ break;
+ }
+ if(!all) {
+ return sc->NIL;
+ }
+ }
+ if (x != sc->NIL) {
+ return car(y);
+ }
+ return sc->NIL;
+}
+
+#else /* USE_ALIST_ENV */
+
+static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
+{
+ sc->envir = immutable_cons(sc, sc->NIL, old_env);
+ setenvironment(sc->envir);
+}
+
+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
+ pointer variable, pointer value)
+{
+ car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
+}
+
+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
+{
+ pointer x,y;
+ for (x = env; x != sc->NIL; x = cdr(x)) {
+ for (y = car(x); y != sc->NIL; y = cdr(y)) {
+ if (caar(y) == hdl) {
+ break;
+ }
+ }
+ if (y != sc->NIL) {
+ break;
+ }
+ if(!all) {
+ return sc->NIL;
+ }
+ }
+ if (x != sc->NIL) {
+ return car(y);
+ }
+ return sc->NIL;
+}
+
+#endif /* USE_ALIST_ENV else */
+
+static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
+{
+ new_slot_spec_in_env(sc, sc->envir, variable, value);
+}
+
+static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
+{
+ cdr(slot) = value;
+}
+
+static INLINE pointer slot_value_in_env(pointer slot)
+{
+ return cdr(slot);
+}
+
+/* ========== Evaluation Cycle ========== */
+
+
+static pointer _Error_1(scheme *sc, const char *s, pointer a) {
+ const char *str = s;
+#if USE_ERROR_HOOK
+ pointer x;
+ pointer hdl=sc->ERROR_HOOK;
+#endif
+
+#if SHOW_ERROR_LINE
+ char sbuf[STRBUFFSIZE];
+
+ /* make sure error is not in REPL */
+ if (sc->load_stack[sc->file_i].kind & port_file &&
+ sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
+ int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
+ const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
+
+ /* should never happen */
+ if(!fname) fname = "<unknown>";
+
+ /* we started from 0 */
+ ln++;
+ snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
+
+ str = (const char*)sbuf;
+ }
+#endif
+
+#if USE_ERROR_HOOK
+ x=find_slot_in_env(sc,sc->envir,hdl,1);
+ if (x != sc->NIL) {
+ if(a!=0) {
+ sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
+ } else {
+ sc->code = sc->NIL;
+ }
+ sc->code = cons(sc, mk_string(sc, str), sc->code);
+ setimmutable(car(sc->code));
+ sc->code = cons(sc, slot_value_in_env(x), sc->code);
+ sc->op = (int)OP_EVAL;
+ return sc->T;
+ }
+#endif
+
+ if(a!=0) {
+ sc->args = cons(sc, (a), sc->NIL);
+ } else {
+ sc->args = sc->NIL;
+ }
+ sc->args = cons(sc, mk_string(sc, str), sc->args);
+ setimmutable(car(sc->args));
+ sc->op = (int)OP_ERR0;
+ return sc->T;
+}
+#define Error_1(sc,s,a) return _Error_1(sc,s,a)
+#define Error_0(sc,s) return _Error_1(sc,s,0)
+
+/* Too small to turn into function */
+# define BEGIN do {
+# define END } while (0)
+#define s_goto(sc,a) BEGIN \
+ sc->op = (int)(a); \
+ return sc->T; END
+
+#define s_return(sc,a) return _s_return(sc,a)
+
+#ifndef USE_SCHEME_STACK
+
+/* this structure holds all the interpreter's registers */
+struct dump_stack_frame {
+ enum scheme_opcodes op;
+ pointer args;
+ pointer envir;
+ pointer code;
+};
+
+#define STACK_GROWTH 3
+
+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
+{
+ int nframes = (int)sc->dump;
+ struct dump_stack_frame *next_frame;
+
+ /* enough room for the next frame? */
+ if (nframes >= sc->dump_size) {
+ sc->dump_size += STACK_GROWTH;
+ /* alas there is no sc->realloc */
+ sc->dump_base = realloc(sc->dump_base,
+ sizeof(struct dump_stack_frame) * sc->dump_size);
+ }
+ next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
+ next_frame->op = op;
+ next_frame->args = args;
+ next_frame->envir = sc->envir;
+ next_frame->code = code;
+ sc->dump = (pointer)(nframes+1);
+}
+
+static pointer _s_return(scheme *sc, pointer a)
+{
+ int nframes = (int)sc->dump;
+ struct dump_stack_frame *frame;
+
+ sc->value = (a);
+ if (nframes <= 0) {
+ return sc->NIL;
+ }
+ nframes--;
+ frame = (struct dump_stack_frame *)sc->dump_base + nframes;
+ sc->op = frame->op;
+ sc->args = frame->args;
+ sc->envir = frame->envir;
+ sc->code = frame->code;
+ sc->dump = (pointer)nframes;
+ return sc->T;
+}
+
+static INLINE void dump_stack_reset(scheme *sc)
+{
+ /* in this implementation, sc->dump is the number of frames on the stack */
+ sc->dump = (pointer)0;
+}
+
+static INLINE void dump_stack_initialize(scheme *sc)
+{
+ sc->dump_size = 0;
+ sc->dump_base = NULL;
+ dump_stack_reset(sc);
+}
+
+static void dump_stack_free(scheme *sc)
+{
+ free(sc->dump_base);
+ sc->dump_base = NULL;
+ sc->dump = (pointer)0;
+ sc->dump_size = 0;
+}
+
+static INLINE void dump_stack_mark(scheme *sc)
+{
+ int nframes = (int)sc->dump;
+ int i;
+ for(i=0; i<nframes; i++) {
+ struct dump_stack_frame *frame;
+ frame = (struct dump_stack_frame *)sc->dump_base + i;
+ mark(frame->args);
+ mark(frame->envir);
+ mark(frame->code);
+ }
+}
+
+#else
+
+static INLINE void dump_stack_reset(scheme *sc)
+{
+ sc->dump = sc->NIL;
+}
+
+static INLINE void dump_stack_initialize(scheme *sc)
+{
+ dump_stack_reset(sc);
+}
+
+static void dump_stack_free(scheme *sc)
+{
+ sc->dump = sc->NIL;
+}
+
+static pointer _s_return(scheme *sc, pointer a) {
+ sc->value = (a);
+ if(sc->dump==sc->NIL) return sc->NIL;
+ sc->op = ivalue(car(sc->dump));
+ sc->args = cadr(sc->dump);
+ sc->envir = caddr(sc->dump);
+ sc->code = cadddr(sc->dump);
+ sc->dump = cddddr(sc->dump);
+ return sc->T;
+}
+
+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
+ sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
+ sc->dump = cons(sc, (args), sc->dump);
+ sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
+}
+
+static INLINE void dump_stack_mark(scheme *sc)
+{
+ mark(sc->dump);
+}
+#endif
+
+#define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
+
+static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
+ pointer x, y;
+
+ switch (op) {
+ case OP_LOAD: /* load */
+ if(file_interactive(sc)) {
+ fprintf(sc->outport->_object._port->rep.stdio.file,
+ "Loading %s\n", strvalue(car(sc->args)));
+ }
+ if (!file_push(sc,strvalue(car(sc->args)))) {
+ Error_1(sc,"unable to open", car(sc->args));
+ }
+ else
+ {
+ sc->args = mk_integer(sc,sc->file_i);
+ s_goto(sc,OP_T0LVL);
+ }
+
+ case OP_T0LVL: /* top level */
+ /* If we reached the end of file, this loop is done. */
+ if(sc->loadport->_object._port->kind & port_saw_EOF)
+ {
+ if(sc->file_i == 0)
+ {
+ sc->args=sc->NIL;
+ s_goto(sc,OP_QUIT);
+ }
+ else
+ {
+ file_pop(sc);
+ s_return(sc,sc->value);
+ }
+ /* NOTREACHED */
+ }
+
+ /* If interactive, be nice to user. */
+ if(file_interactive(sc))
+ {
+ sc->envir = sc->global_env;
+ dump_stack_reset(sc);
+ putstr(sc,"\n");
+ putstr(sc,prompt);
+ }
+
+ /* Set up another iteration of REPL */
+ sc->nesting=0;
+ sc->save_inport=sc->inport;
+ sc->inport = sc->loadport;
+ s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
+ s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
+ s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
+ s_goto(sc,OP_READ_INTERNAL);
+
+ case OP_T1LVL: /* top level */
+ sc->code = sc->value;
+ sc->inport=sc->save_inport;
+ s_goto(sc,OP_EVAL);
+
+ case OP_READ_INTERNAL: /* internal read */
+ sc->tok = token(sc);
+ if(sc->tok==TOK_EOF)
+ { s_return(sc,sc->EOF_OBJ); }
+ s_goto(sc,OP_RDSEXPR);
+
+ case OP_GENSYM:
+ s_return(sc, gensym(sc));
+
+ case OP_VALUEPRINT: /* print evaluation result */
+ /* OP_VALUEPRINT is always pushed, because when changing from
+ non-interactive to interactive mode, it needs to be
+ already on the stack */
+ if(sc->tracing) {
+ putstr(sc,"\nGives: ");
+ }
+ if(file_interactive(sc) || sc->print_output) {
+ sc->print_flag = 1;
+ sc->args = sc->value;
+ s_goto(sc,OP_P0LIST);
+ } else {
+ s_return(sc,sc->value);
+ }
+
+ case OP_EVAL: /* main part of evaluation */
+#if USE_TRACING
+ if(sc->tracing) {
+ /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
+ s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
+ sc->args=sc->code;
+ putstr(sc,"\nEval: ");
+ s_goto(sc,OP_P0LIST);
+ }
+ /* fall through */
+ case OP_REAL_EVAL:
+#endif
+ if (is_symbol(sc->code)) { /* symbol */
+ x=find_slot_in_env(sc,sc->envir,sc->code,1);
+ if (x != sc->NIL) {
+ s_return(sc,slot_value_in_env(x));
+ } else {
+ Error_1(sc,"eval: unbound variable:", sc->code);
+ }
+ } else if (is_pair(sc->code)) {
+ if (is_syntax(x = car(sc->code))) { /* SYNTAX */
+ sc->code = cdr(sc->code);
+ s_goto(sc,syntaxnum(x));
+ } else {/* first, eval top element and eval arguments */
+ s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
+ /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+ }
+ } else {
+ s_return(sc,sc->code);
+ }
+
+ case OP_E0ARGS: /* eval arguments */
+ if (is_macro(sc->value)) { /* macro expansion */
+ s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
+ sc->args = cons(sc,sc->code, sc->NIL);
+ sc->code = sc->value;
+ s_goto(sc,OP_APPLY);
+ } else {
+ sc->code = cdr(sc->code);
+ s_goto(sc,OP_E1ARGS);
+ }
+
+ case OP_E1ARGS: /* eval arguments */
+ sc->args = cons(sc, sc->value, sc->args);
+ if (is_pair(sc->code)) { /* continue */
+ s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
+ sc->code = car(sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_EVAL);
+ } else { /* end */
+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+ sc->code = car(sc->args);
+ sc->args = cdr(sc->args);
+ s_goto(sc,OP_APPLY);
+ }
+
+#if USE_TRACING
+ case OP_TRACING: {
+ int tr=sc->tracing;
+ sc->tracing=ivalue(car(sc->args));
+ s_return(sc,mk_integer(sc,tr));
+ }
+#endif
+
+ case OP_APPLY: /* apply 'code' to 'args' */
+#if USE_TRACING
+ if(sc->tracing) {
+ s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
+ sc->print_flag = 1;
+ /* sc->args=cons(sc,sc->code,sc->args);*/
+ putstr(sc,"\nApply to: ");
+ s_goto(sc,OP_P0LIST);
+ }
+ /* fall through */
+ case OP_REAL_APPLY:
+#endif
+ if (is_proc(sc->code)) {
+ s_goto(sc,procnum(sc->code)); /* PROCEDURE */
+ } else if (is_foreign(sc->code))
+ {
+ /* Keep nested calls from GC'ing the arglist */
+ push_recent_alloc(sc,sc->args,sc->NIL);
+ sc->foreign_error = sc->NIL;
+ x=sc->code->_object._ff(sc,sc->args);
+ if (sc->foreign_error == sc->NIL) {
+ s_return(sc,x);
+ } else {
+ x = sc->foreign_error;
+ sc->foreign_error = sc->NIL;
+ Error_1 (sc, string_value (car (x)), cdr (x));
+ }
+ } else if (is_closure(sc->code) || is_macro(sc->code)
+ || is_promise(sc->code)) { /* CLOSURE */
+ /* Should not accept promise */
+ /* make environment */
+ new_frame_in_env(sc, closure_env(sc->code));
+ for (x = car(closure_code(sc->code)), y = sc->args;
+ is_pair(x); x = cdr(x), y = cdr(y)) {
+ if (y == sc->NIL) {
+ Error_0(sc,"not enough arguments");
+ } else {
+ new_slot_in_env(sc, car(x), car(y));
+ }
+ }
+ if (x == sc->NIL) {
+ /*--
+ * if (y != sc->NIL) {
+ * Error_0(sc,"too many arguments");
+ * }
+ */
+ } else if (is_symbol(x))
+ new_slot_in_env(sc, x, y);
+ else {
+ Error_1(sc,"syntax error in closure: not a symbol:", x);
+ }
+ sc->code = cdr(closure_code(sc->code));
+ sc->args = sc->NIL;
+ s_goto(sc,OP_BEGIN);
+ } else if (is_continuation(sc->code)) { /* CONTINUATION */
+ sc->dump = cont_dump(sc->code);
+ s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
+ } else {
+ Error_0(sc,"illegal function");
+ }
+
+ case OP_DOMACRO: /* do macro */
+ sc->code = sc->value;
+ s_goto(sc,OP_EVAL);
+
+#if 1
+ case OP_LAMBDA: /* lambda */
+ /* If the hook is defined, apply it to sc->code, otherwise
+ set sc->value fall thru */
+ {
+ pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
+ if(f==sc->NIL) {
+ sc->value = sc->code;
+ /* Fallthru */
+ } else {
+ s_save(sc,OP_LAMBDA1,sc->args,sc->code);
+ sc->args=cons(sc,sc->code,sc->NIL);
+ sc->code=slot_value_in_env(f);
+ s_goto(sc,OP_APPLY);
+ }
+ }
+
+ case OP_LAMBDA1:
+ s_return(sc,mk_closure(sc, sc->value, sc->envir));
+
+#else
+ case OP_LAMBDA: /* lambda */
+ s_return(sc,mk_closure(sc, sc->code, sc->envir));
+
+#endif
+
+ case OP_MKCLOSURE: /* make-closure */
+ x=car(sc->args);
+ if(car(x)==sc->LAMBDA) {
+ x=cdr(x);
+ }
+ if(cdr(sc->args)==sc->NIL) {
+ y=sc->envir;
+ } else {
+ y=cadr(sc->args);
+ }
+ s_return(sc,mk_closure(sc, x, y));
+
+ case OP_QUOTE: /* quote */
+ s_return(sc,car(sc->code));
+
+ case OP_DEF0: /* define */
+ if(is_immutable(car(sc->code)))
+ Error_1(sc,"define: unable to alter immutable", car(sc->code));
+
+ if (is_pair(car(sc->code))) {
+ x = caar(sc->code);
+ sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
+ } else {
+ x = car(sc->code);
+ sc->code = cadr(sc->code);
+ }
+ if (!is_symbol(x)) {
+ Error_0(sc,"variable is not a symbol");
+ }
+ s_save(sc,OP_DEF1, sc->NIL, x);
+ s_goto(sc,OP_EVAL);
+
+ case OP_DEF1: /* define */
+ x=find_slot_in_env(sc,sc->envir,sc->code,0);
+ if (x != sc->NIL) {
+ set_slot_in_env(sc, x, sc->value);
+ } else {
+ new_slot_in_env(sc, sc->code, sc->value);
+ }
+ s_return(sc,sc->code);
+
+
+ case OP_DEFP: /* defined? */
+ x=sc->envir;
+ if(cdr(sc->args)!=sc->NIL) {
+ x=cadr(sc->args);
+ }
+ s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
+
+ case OP_SET0: /* set! */
+ if(is_immutable(car(sc->code)))
+ Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
+ s_save(sc,OP_SET1, sc->NIL, car(sc->code));
+ sc->code = cadr(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_SET1: /* set! */
+ y=find_slot_in_env(sc,sc->envir,sc->code,1);
+ if (y != sc->NIL) {
+ set_slot_in_env(sc, y, sc->value);
+ s_return(sc,sc->value);
+ } else {
+ Error_1(sc,"set!: unbound variable:", sc->code);
+ }
+
+ case OP_BEGIN: /* begin */
+ if (!is_pair(sc->code)) {
+ s_return(sc,sc->code);
+ }
+ if (cdr(sc->code) != sc->NIL) {
+ s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
+ }
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_IF0: /* if */
+ s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_IF1: /* if */
+ if (is_true(sc->value))
+ sc->code = car(sc->code);
+ else
+ sc->code = cadr(sc->code); /* (if #f 1) ==> () because
+ * car(sc->NIL) = sc->NIL */
+ s_goto(sc,OP_EVAL);
+
+ case OP_LET0: /* let */
+ sc->args = sc->NIL;
+ sc->value = sc->code;
+ sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
+ s_goto(sc,OP_LET1);
+
+ case OP_LET1: /* let (calculate parameters) */
+ sc->args = cons(sc, sc->value, sc->args);
+ if (is_pair(sc->code)) { /* continue */
+ if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
+ Error_1(sc, "Bad syntax of binding spec in let :", car(sc->code));
+ }
+ s_save(sc,OP_LET1, sc->args, cdr(sc->code));
+ sc->code = cadar(sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_EVAL);
+ } else { /* end */
+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+ sc->code = car(sc->args);
+ sc->args = cdr(sc->args);
+ s_goto(sc,OP_LET2);
+ }
+
+ case OP_LET2: /* let */
+ new_frame_in_env(sc, sc->envir);
+ for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
+ y != sc->NIL; x = cdr(x), y = cdr(y)) {
+ new_slot_in_env(sc, caar(x), car(y));
+ }
+ if (is_symbol(car(sc->code))) { /* named let */
+ for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
+ if (!is_pair(x))
+ Error_1(sc, "Bad syntax of binding in let :", x);
+ if (!is_list(sc, car(x)))
+ Error_1(sc, "Bad syntax of binding in let :", car(x));
+ sc->args = cons(sc, caar(x), sc->args);
+ }
+ x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
+ new_slot_in_env(sc, car(sc->code), x);
+ sc->code = cddr(sc->code);
+ sc->args = sc->NIL;
+ } else {
+ sc->code = cdr(sc->code);
+ sc->args = sc->NIL;
+ }
+ s_goto(sc,OP_BEGIN);
+
+ case OP_LET0AST: /* let* */
+ if (car(sc->code) == sc->NIL) {
+ new_frame_in_env(sc, sc->envir);
+ sc->code = cdr(sc->code);
+ s_goto(sc,OP_BEGIN);
+ }
+ if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
+ Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
+ }
+ s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
+ sc->code = cadaar(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_LET1AST: /* let* (make new frame) */
+ new_frame_in_env(sc, sc->envir);
+ s_goto(sc,OP_LET2AST);
+
+ case OP_LET2AST: /* let* (calculate parameters) */
+ new_slot_in_env(sc, caar(sc->code), sc->value);
+ sc->code = cdr(sc->code);
+ if (is_pair(sc->code)) { /* continue */
+ s_save(sc,OP_LET2AST, sc->args, sc->code);
+ sc->code = cadar(sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_EVAL);
+ } else { /* end */
+ sc->code = sc->args;
+ sc->args = sc->NIL;
+ s_goto(sc,OP_BEGIN);
+ }
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T;
+}
+
+static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
+ pointer x, y;
+
+ switch (op) {
+ case OP_LET0REC: /* letrec */
+ new_frame_in_env(sc, sc->envir);
+ sc->args = sc->NIL;
+ sc->value = sc->code;
+ sc->code = car(sc->code);
+ s_goto(sc,OP_LET1REC);
+
+ case OP_LET1REC: /* letrec (calculate parameters) */
+ sc->args = cons(sc, sc->value, sc->args);
+ if (is_pair(sc->code)) { /* continue */
+ if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
+ Error_1(sc,"Bad syntax of binding spec in letrec :",car(sc->code));
+ }
+ s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
+ sc->code = cadar(sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_EVAL);
+ } else { /* end */
+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
+ sc->code = car(sc->args);
+ sc->args = cdr(sc->args);
+ s_goto(sc,OP_LET2REC);
+ }
+
+ case OP_LET2REC: /* letrec */
+ for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
+ new_slot_in_env(sc, caar(x), car(y));
+ }
+ sc->code = cdr(sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_BEGIN);
+
+ case OP_COND0: /* cond */
+ if (!is_pair(sc->code)) {
+ Error_0(sc,"syntax error in cond");
+ }
+ s_save(sc,OP_COND1, sc->NIL, sc->code);
+ sc->code = caar(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_COND1: /* cond */
+ if (is_true(sc->value)) {
+ if ((sc->code = cdar(sc->code)) == sc->NIL) {
+ s_return(sc,sc->value);
+ }
+ if(!sc->code) {
+ Error_0(sc,"syntax error in cond");
+ }
+ if(car(sc->code)==sc->FEED_TO) {
+ if(!is_pair(cdr(sc->code))) {
+ Error_0(sc,"syntax error in cond");
+ }
+ x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
+ sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
+ s_goto(sc,OP_EVAL);
+ }
+ s_goto(sc,OP_BEGIN);
+ } else {
+ if ((sc->code = cdr(sc->code)) == sc->NIL) {
+ s_return(sc,sc->NIL);
+ } else {
+ s_save(sc,OP_COND1, sc->NIL, sc->code);
+ sc->code = caar(sc->code);
+ s_goto(sc,OP_EVAL);
+ }
+ }
+
+ case OP_DELAY: /* delay */
+ x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
+ typeflag(x)=T_PROMISE;
+ s_return(sc,x);
+
+ case OP_AND0: /* and */
+ if (sc->code == sc->NIL) {
+ s_return(sc,sc->T);
+ }
+ s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_AND1: /* and */
+ if (is_false(sc->value)) {
+ s_return(sc,sc->value);
+ } else if (sc->code == sc->NIL) {
+ s_return(sc,sc->value);
+ } else {
+ s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+ }
+
+ case OP_OR0: /* or */
+ if (sc->code == sc->NIL) {
+ s_return(sc,sc->F);
+ }
+ s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_OR1: /* or */
+ if (is_true(sc->value)) {
+ s_return(sc,sc->value);
+ } else if (sc->code == sc->NIL) {
+ s_return(sc,sc->value);
+ } else {
+ s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+ }
+
+ case OP_C0STREAM: /* cons-stream */
+ s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_C1STREAM: /* cons-stream */
+ sc->args = sc->value; /* save sc->value to register sc->args for gc */
+ x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
+ typeflag(x)=T_PROMISE;
+ s_return(sc,cons(sc, sc->args, x));
+
+ case OP_MACRO0: /* macro */
+ if (is_pair(car(sc->code))) {
+ x = caar(sc->code);
+ sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
+ } else {
+ x = car(sc->code);
+ sc->code = cadr(sc->code);
+ }
+ if (!is_symbol(x)) {
+ Error_0(sc,"variable is not a symbol");
+ }
+ s_save(sc,OP_MACRO1, sc->NIL, x);
+ s_goto(sc,OP_EVAL);
+
+ case OP_MACRO1: /* macro */
+ typeflag(sc->value) = T_MACRO;
+ x = find_slot_in_env(sc, sc->envir, sc->code, 0);
+ if (x != sc->NIL) {
+ set_slot_in_env(sc, x, sc->value);
+ } else {
+ new_slot_in_env(sc, sc->code, sc->value);
+ }
+ s_return(sc,sc->code);
+
+ case OP_CASE0: /* case */
+ s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
+ sc->code = car(sc->code);
+ s_goto(sc,OP_EVAL);
+
+ case OP_CASE1: /* case */
+ for (x = sc->code; x != sc->NIL; x = cdr(x)) {
+ if (!is_pair(y = caar(x))) {
+ break;
+ }
+ for ( ; y != sc->NIL; y = cdr(y)) {
+ if (eqv(car(y), sc->value)) {
+ break;
+ }
+ }
+ if (y != sc->NIL) {
+ break;
+ }
+ }
+ if (x != sc->NIL) {
+ if (is_pair(caar(x))) {
+ sc->code = cdar(x);
+ s_goto(sc,OP_BEGIN);
+ } else {/* else */
+ s_save(sc,OP_CASE2, sc->NIL, cdar(x));
+ sc->code = caar(x);
+ s_goto(sc,OP_EVAL);
+ }
+ } else {
+ s_return(sc,sc->NIL);
+ }
+
+ case OP_CASE2: /* case */
+ if (is_true(sc->value)) {
+ s_goto(sc,OP_BEGIN);
+ } else {
+ s_return(sc,sc->NIL);
+ }
+
+ case OP_PAPPLY: /* apply */
+ sc->code = car(sc->args);
+ sc->args = list_star(sc,cdr(sc->args));
+ /*sc->args = cadr(sc->args);*/
+ s_goto(sc,OP_APPLY);
+
+ case OP_PEVAL: /* eval */
+ if(cdr(sc->args)!=sc->NIL) {
+ sc->envir=cadr(sc->args);
+ }
+ sc->code = car(sc->args);
+ s_goto(sc,OP_EVAL);
+
+ case OP_CONTINUATION: /* call-with-current-continuation */
+ sc->code = car(sc->args);
+ sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
+ s_goto(sc,OP_APPLY);
+
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T;
+}
+
+static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
+ pointer x;
+ num v;
+#if USE_MATH
+ double dd;
+#endif
+
+ switch (op) {
+#if USE_MATH
+ case OP_INEX2EX: /* inexact->exact */
+ x=car(sc->args);
+ if(num_is_integer(x)) {
+ s_return(sc,x);
+ } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
+ s_return(sc,mk_integer(sc,ivalue(x)));
+ } else {
+ Error_1(sc,"inexact->exact: not integral:",x);
+ }
+
+ case OP_EXP:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, exp(rvalue(x))));
+
+ case OP_LOG:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, log(rvalue(x))));
+
+ case OP_SIN:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, sin(rvalue(x))));
+
+ case OP_COS:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, cos(rvalue(x))));
+
+ case OP_TAN:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, tan(rvalue(x))));
+
+ case OP_ASIN:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, asin(rvalue(x))));
+
+ case OP_ACOS:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, acos(rvalue(x))));
+
+ case OP_ATAN:
+ x=car(sc->args);
+ if(cdr(sc->args)==sc->NIL) {
+ s_return(sc, mk_real(sc, atan(rvalue(x))));
+ } else {
+ pointer y=cadr(sc->args);
+ s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
+ }
+
+ case OP_SQRT:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, sqrt(rvalue(x))));
+
+ case OP_EXPT: {
+ double result;
+ int real_result=1;
+ pointer y=cadr(sc->args);
+ x=car(sc->args);
+ if (num_is_integer(x) && num_is_integer(y))
+ real_result=0;
+ /* This 'if' is an R5RS compatibility fix. */
+ /* NOTE: Remove this 'if' fix for R6RS. */
+ if (rvalue(x) == 0 && rvalue(y) < 0) {
+ result = 0.0;
+ } else {
+ result = pow(rvalue(x),rvalue(y));
+ }
+ /* Before returning integer result make sure we can. */
+ /* If the test fails, result is too big for integer. */
+ if (!real_result)
+ {
+ long result_as_long = (long)result;
+ if (result != (double)result_as_long)
+ real_result = 1;
+ }
+ if (real_result) {
+ s_return(sc, mk_real(sc, result));
+ } else {
+ s_return(sc, mk_integer(sc, result));
+ }
+ }
+
+ case OP_FLOOR:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, floor(rvalue(x))));
+
+ case OP_CEILING:
+ x=car(sc->args);
+ s_return(sc, mk_real(sc, ceil(rvalue(x))));
+
+ case OP_TRUNCATE : {
+ double rvalue_of_x ;
+ x=car(sc->args);
+ rvalue_of_x = rvalue(x) ;
+ if (rvalue_of_x > 0) {
+ s_return(sc, mk_real(sc, floor(rvalue_of_x)));
+ } else {
+ s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
+ }
+ }
+
+ case OP_ROUND:
+ x=car(sc->args);
+ if (num_is_integer(x))
+ s_return(sc, x);
+ s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
+#endif
+
+ case OP_ADD: /* + */
+ v=num_zero;
+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+ v=num_add(v,nvalue(car(x)));
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_MUL: /* * */
+ v=num_one;
+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+ v=num_mul(v,nvalue(car(x)));
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_SUB: /* - */
+ if(cdr(sc->args)==sc->NIL) {
+ x=sc->args;
+ v=num_zero;
+ } else {
+ x = cdr(sc->args);
+ v = nvalue(car(sc->args));
+ }
+ for (; x != sc->NIL; x = cdr(x)) {
+ v=num_sub(v,nvalue(car(x)));
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_DIV: /* / */
+ if(cdr(sc->args)==sc->NIL) {
+ x=sc->args;
+ v=num_one;
+ } else {
+ x = cdr(sc->args);
+ v = nvalue(car(sc->args));
+ }
+ for (; x != sc->NIL; x = cdr(x)) {
+ if (!is_zero_double(rvalue(car(x))))
+ v=num_div(v,nvalue(car(x)));
+ else {
+ Error_0(sc,"/: division by zero");
+ }
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_INTDIV: /* quotient */
+ if(cdr(sc->args)==sc->NIL) {
+ x=sc->args;
+ v=num_one;
+ } else {
+ x = cdr(sc->args);
+ v = nvalue(car(sc->args));
+ }
+ for (; x != sc->NIL; x = cdr(x)) {
+ if (ivalue(car(x)) != 0)
+ v=num_intdiv(v,nvalue(car(x)));
+ else {
+ Error_0(sc,"quotient: division by zero");
+ }
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_REM: /* remainder */
+ v = nvalue(car(sc->args));
+ if (ivalue(cadr(sc->args)) != 0)
+ v=num_rem(v,nvalue(cadr(sc->args)));
+ else {
+ Error_0(sc,"remainder: division by zero");
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_MOD: /* modulo */
+ v = nvalue(car(sc->args));
+ if (ivalue(cadr(sc->args)) != 0)
+ v=num_mod(v,nvalue(cadr(sc->args)));
+ else {
+ Error_0(sc,"modulo: division by zero");
+ }
+ s_return(sc,mk_number(sc, v));
+
+ case OP_CAR: /* car */
+ s_return(sc,caar(sc->args));
+
+ case OP_CDR: /* cdr */
+ s_return(sc,cdar(sc->args));
+
+ case OP_CONS: /* cons */
+ cdr(sc->args) = cadr(sc->args);
+ s_return(sc,sc->args);
+
+ case OP_SETCAR: /* set-car! */
+ if(!is_immutable(car(sc->args))) {
+ caar(sc->args) = cadr(sc->args);
+ s_return(sc,car(sc->args));
+ } else {
+ Error_0(sc,"set-car!: unable to alter immutable pair");
+ }
+
+ case OP_SETCDR: /* set-cdr! */
+ if(!is_immutable(car(sc->args))) {
+ cdar(sc->args) = cadr(sc->args);
+ s_return(sc,car(sc->args));
+ } else {
+ Error_0(sc,"set-cdr!: unable to alter immutable pair");
+ }
+
+ case OP_CHAR2INT: { /* char->integer */
+ gunichar c;
+ c=ivalue(car(sc->args));
+ s_return(sc,mk_integer(sc,c));
+ }
+
+ case OP_INT2CHAR: { /* integer->char */
+ gunichar c;
+ c=(gunichar)ivalue(car(sc->args));
+ s_return(sc,mk_character(sc,c));
+ }
+
+ case OP_CHARUPCASE: {
+ gunichar c;
+ c=(gunichar)ivalue(car(sc->args));
+ c=g_unichar_toupper(c);
+ s_return(sc,mk_character(sc,c));
+ }
+
+ case OP_CHARDNCASE: {
+ gunichar c;
+ c=(gunichar)ivalue(car(sc->args));
+ c=g_unichar_tolower(c);
+ s_return(sc,mk_character(sc,c));
+ }
+
+ case OP_STR2SYM: /* string->symbol */
+ s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
+
+ case OP_STR2ATOM: /* string->atom */ {
+ char *s=strvalue(car(sc->args));
+ long pf = 0;
+ if(cdr(sc->args)!=sc->NIL) {
+ /* we know cadr(sc->args) is a natural number */
+ /* see if it is 2, 8, 10, or 16, or error */
+ pf = ivalue_unchecked(cadr(sc->args));
+ if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
+ /* base is OK */
+ }
+ else {
+ pf = -1;
+ }
+ }
+ if (pf < 0) {
+ Error_1(sc, "string->atom: bad base:", cadr(sc->args));
+ } else if(*s=='#') /* no use of base! */ {
+ s_return(sc, mk_sharp_const(sc, s+1));
+ } else {
+ if (pf == 0 || pf == 10) {
+ s_return(sc, mk_atom(sc, s));
+ }
+ else {
+ char *ep;
+ long iv = strtol(s,&ep,(int )pf);
+ if (*ep == 0) {
+ s_return(sc, mk_integer(sc, iv));
+ }
+ else {
+ s_return(sc, sc->F);
+ }
+ }
+ }
+ }
+
+ case OP_SYM2STR: /* symbol->string */
+ x=mk_string(sc,symname(car(sc->args)));
+ setimmutable(x);
+ s_return(sc,x);
+
+ case OP_ATOM2STR: /* atom->string */ {
+ long pf = 0;
+ x=car(sc->args);
+ if(cdr(sc->args)!=sc->NIL) {
+ /* we know cadr(sc->args) is a natural number */
+ /* see if it is 2, 8, 10, or 16, or error */
+ pf = ivalue_unchecked(cadr(sc->args));
+ if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
+ /* base is OK */
+ }
+ else {
+ pf = -1;
+ }
+ }
+ if (pf < 0) {
+ Error_1(sc, "atom->string: bad base:", cadr(sc->args));
+ } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
+ char *p;
+ int len;
+ atom2str(sc,x,(int )pf,&p,&len);
+ s_return(sc,mk_counted_string(sc,p,len));
+ } else {
+ Error_1(sc, "atom->string: not an atom:", x);
+ }
+ }
+
+ case OP_MKSTRING: { /* make-string */
+ gunichar fill=' ';
+ int len;
+
+ len=ivalue(car(sc->args));
+
+ if(cdr(sc->args)!=sc->NIL) {
+ fill=charvalue(cadr(sc->args));
+ }
+ s_return(sc,mk_empty_string(sc,len,fill));
+ }
+
+ case OP_STRLEN: /* string-length */
+ s_return(sc,mk_integer(sc,g_utf8_strlen(strvalue(car(sc->args)), -1)));
+
+ case OP_STRREF: { /* string-ref */
+ char *str;
+ int index;
+
+ str=strvalue(car(sc->args));
+
+ index=ivalue(cadr(sc->args));
+
+ if(index>=g_utf8_strlen(strvalue(car(sc->args)), -1)) {
+ Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
+ }
+
+ str = g_utf8_offset_to_pointer(str, (long)index);
+ s_return(sc,mk_character(sc, g_utf8_get_char(str)));
+ }
+
+ case OP_STRSET: { /* string-set! */
+ pointer a;
+ char *str;
+ int index;
+ gunichar c;
+ char utf8[7];
+ int utf8_len;
+ int newlen;
+ char *p1, *p2;
+ int p1_len;
+ int p2_len;
+ char *newstr;
+
+ a=car(sc->args);
+ if(is_immutable(a)) {
+ Error_1(sc,"string-set!: unable to alter immutable string:",a);
+ }
+
+ str=strvalue(a);
+ index=ivalue(cadr(sc->args));
+ if(index>=g_utf8_strlen(str, -1)) {
+ Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
+ }
+
+ c=charvalue(caddr(sc->args));
+ utf8_len = g_unichar_to_utf8(c, utf8);
+
+ p1 = g_utf8_offset_to_pointer(str, (long)index);
+ p2 = g_utf8_offset_to_pointer(str, (long)index+1);
+ p1_len = p1-str;
+ p2_len = strlen(p2);
+
+ newlen = p1_len+utf8_len+p2_len;
+ newstr = (char *)sc->malloc(newlen+1);
+ if (newstr == NULL) {
+ sc->no_memory=1;
+ Error_1(sc,"string-set!: No memory to alter string:",car(sc->args));
+ }
+
+ if (p1_len > 0)
+ memcpy(newstr, str, p1_len);
+ memcpy(newstr+p1_len, utf8, utf8_len);
+ if (p2_len > 0)
+ memcpy(newstr+p1_len+utf8_len, p2, p2_len);
+ newstr[newlen] = '\0';
+
+ free(strvalue(a));
+ strvalue(a)=newstr;
+ strlength(a)=g_utf8_strlen(newstr, -1);
+
+ s_return(sc,a);
+ }
+
+ case OP_STRAPPEND: { /* string-append */
+ /* in 1.29 string-append was in Scheme in init.scm but was too slow */
+ int len = 0;
+ pointer car_x;
+ char *newstr;
+ char *pos;
+ char *end;
+
+ /* compute needed length for new string */
+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+ car_x = car(x);
+ end = g_utf8_offset_to_pointer(strvalue(car_x), (long)strlength(car_x));
+ len += end - strvalue(car_x);
+ }
+
+ newstr = (char *)sc->malloc(len+1);
+ if (newstr == NULL) {
+ sc->no_memory=1;
+ Error_1(sc,"string-set!: No memory to append strings:",car(sc->args));
+ }
+
+ /* store the contents of the argument strings into the new string */
+ pos = newstr;
+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
+ car_x = car(x);
+ end = g_utf8_offset_to_pointer(strvalue(car_x), (long)strlength(car_x));
+ len = end - strvalue(car_x);
+ memcpy(pos, strvalue(car_x), len);
+ pos += len;
+ }
+ *pos = '\0';
+
+ car_x = mk_string(sc, newstr);
+ g_free(newstr);
+
+ s_return(sc, car_x);
+ }
+
+ case OP_SUBSTR: { /* substring */
+ char *str;
+ char *beg;
+ char *end;
+ int index0;
+ int index1;
+ int len;
+ pointer x;
+
+ str=strvalue(car(sc->args));
+
+ index0=ivalue(cadr(sc->args));
+
+ if(index0>g_utf8_strlen(str, -1)) {
+ Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
+ }
+
+ if(cddr(sc->args)!=sc->NIL) {
+ index1=ivalue(caddr(sc->args));
+ if(index1>g_utf8_strlen(str, -1) || index1<index0) {
+ Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
+ }
+ } else {
+ index1=g_utf8_strlen(str, -1);
+ }
+
+ /* store the contents of the argument strings into the new string */
+ beg = g_utf8_offset_to_pointer(str, (long)index0);
+ end = g_utf8_offset_to_pointer(str, (long)index1);
+ len=end-beg;
+
+ str = (char *)sc->malloc(len+1);
+ if (str == NULL) {
+ sc->no_memory=1;
+ Error_1(sc,"string-set!: No memory to extract substring:",car(sc->args));
+ }
+
+ memcpy(str, beg, len);
+ str[len] = '\0';
+
+ x = mk_string(sc, str);
+ g_free(str);
+
+ s_return(sc,x);
+ }
+
+ case OP_VECTOR: { /* vector */
+ int i;
+ pointer vec;
+ int len=list_length(sc,sc->args);
+ if(len<0) {
+ Error_1(sc,"vector: not a proper list:",sc->args);
+ }
+ vec=mk_vector(sc,len);
+ if(sc->no_memory) { s_return(sc, sc->sink); }
+ for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
+ set_vector_elem(vec,i,car(x));
+ }
+ s_return(sc,vec);
+ }
+
+ case OP_MKVECTOR: { /* make-vector */
+ pointer fill=sc->NIL;
+ int len;
+ pointer vec;
+
+ len=ivalue(car(sc->args));
+
+ if(cdr(sc->args)!=sc->NIL) {
+ fill=cadr(sc->args);
+ }
+ vec=mk_vector(sc,len);
+ if(sc->no_memory) { s_return(sc, sc->sink); }
+ if(fill!=sc->NIL) {
+ fill_vector(vec,fill);
+ }
+ s_return(sc,vec);
+ }
+
+ case OP_VECLEN: /* vector-length */
+ s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
+
+ case OP_VECREF: { /* vector-ref */
+ int index;
+
+ index=ivalue(cadr(sc->args));
+
+ if(index>=ivalue(car(sc->args))) {
+ Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
+ }
+
+ s_return(sc,vector_elem(car(sc->args),index));
+ }
+
+ case OP_VECSET: { /* vector-set! */
+ int index;
+
+ if(is_immutable(car(sc->args))) {
+ Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
+ }
+
+ index=ivalue(cadr(sc->args));
+ if(index>=ivalue(car(sc->args))) {
+ Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
+ }
+
+ set_vector_elem(car(sc->args),index,caddr(sc->args));
+ s_return(sc,car(sc->args));
+ }
+
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T;
+}
+
+static int is_list(scheme *sc, pointer a)
+{ return list_length(sc,a) >= 0; }
+
+/* Result is:
+ proper list: length
+ circular list: -1
+ not even a pair: -2
+ dotted list: -2 minus length before dot
+*/
+int list_length(scheme *sc, pointer p) {
+ int i=0;
+ pointer slow, fast;
+
+ slow = fast = p;
+ while (1)
+ {
+ if (fast == sc->NIL)
+ return i;
+ if (!is_pair(fast))
+ return -2 - i;
+ fast = cdr(fast);
+ ++i;
+ if (fast == sc->NIL)
+ return i;
+ if (!is_pair(fast))
+ return -2 - i;
+ ++i;
+ fast = cdr(fast);
+
+ /* Safe because we would have already returned if `fast'
+ encountered a non-pair. */
+ slow = cdr(slow);
+ if (fast == slow)
+ {
+ /* the fast pointer has looped back around and caught up
+ with the slow pointer, hence the structure is circular,
+ not of finite length, and therefore not a list */
+ return -1;
+ }
+ }
+}
+
+static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
+ pointer x;
+ num v;
+ int (*comp_func)(num,num)=0;
+
+ switch (op) {
+ case OP_NOT: /* not */
+ s_retbool(is_false(car(sc->args)));
+ case OP_BOOLP: /* boolean? */
+ s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
+ case OP_EOFOBJP: /* boolean? */
+ s_retbool(car(sc->args) == sc->EOF_OBJ);
+ case OP_NULLP: /* null? */
+ s_retbool(car(sc->args) == sc->NIL);
+ case OP_NUMEQ: /* = */
+ case OP_LESS: /* < */
+ case OP_GRE: /* > */
+ case OP_LEQ: /* <= */
+ case OP_GEQ: /* >= */
+ switch(op) {
+ case OP_NUMEQ: comp_func=num_eq; break;
+ case OP_LESS: comp_func=num_lt; break;
+ case OP_GRE: comp_func=num_gt; break;
+ case OP_LEQ: comp_func=num_le; break;
+ case OP_GEQ: comp_func=num_ge; break;
+ default: break; /* Quiet the compiler */
+ }
+ x=sc->args;
+ v=nvalue(car(x));
+ x=cdr(x);
+
+ for (; x != sc->NIL; x = cdr(x)) {
+ if(!comp_func(v,nvalue(car(x)))) {
+ s_retbool(0);
+ }
+ v=nvalue(car(x));
+ }
+ s_retbool(1);
+ case OP_SYMBOLP: /* symbol? */
+ s_retbool(is_symbol(car(sc->args)));
+ case OP_NUMBERP: /* number? */
+ s_retbool(is_number(car(sc->args)));
+ case OP_STRINGP: /* string? */
+ s_retbool(is_string(car(sc->args)));
+ case OP_INTEGERP: /* integer? */
+ s_retbool(is_integer(car(sc->args)));
+ case OP_REALP: /* real? */
+ s_retbool(is_number(car(sc->args))); /* All numbers are real */
+ case OP_CHARP: /* char? */
+ s_retbool(is_character(car(sc->args)));
+#if USE_CHAR_CLASSIFIERS
+ case OP_CHARAP: /* char-alphabetic? */
+ s_retbool(Cisalpha(ivalue(car(sc->args))));
+ case OP_CHARNP: /* char-numeric? */
+ s_retbool(Cisdigit(ivalue(car(sc->args))));
+ case OP_CHARWP: /* char-whitespace? */
+ s_retbool(Cisspace(ivalue(car(sc->args))));
+ case OP_CHARUP: /* char-upper-case? */
+ s_retbool(Cisupper(ivalue(car(sc->args))));
+ case OP_CHARLP: /* char-lower-case? */
+ s_retbool(Cislower(ivalue(car(sc->args))));
+#endif
+ case OP_PORTP: /* port? */
+ s_retbool(is_port(car(sc->args)));
+ case OP_INPORTP: /* input-port? */
+ s_retbool(is_inport(car(sc->args)));
+ case OP_OUTPORTP: /* output-port? */
+ s_retbool(is_outport(car(sc->args)));
+ case OP_PROCP: /* procedure? */
+ /*--
+ * continuation should be procedure by the example
+ * (call-with-current-continuation procedure?) ==> #t
+ * in R^3 report sec. 6.9
+ */
+ s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
+ || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
+ case OP_PAIRP: /* pair? */
+ s_retbool(is_pair(car(sc->args)));
+ case OP_LISTP: /* list? */
+ s_retbool(list_length(sc,car(sc->args)) >= 0);
+ case OP_ENVP: /* environment? */
+ s_retbool(is_environment(car(sc->args)));
+ case OP_VECTORP: /* vector? */
+ s_retbool(is_vector(car(sc->args)));
+ case OP_EQ: /* eq? */
+ s_retbool(car(sc->args) == cadr(sc->args));
+ case OP_EQV: /* eqv? */
+ s_retbool(eqv(car(sc->args), cadr(sc->args)));
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T;
+}
+
+static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
+ pointer x, y;
+
+ switch (op) {
+ case OP_FORCE: /* force */
+ sc->code = car(sc->args);
+ if (is_promise(sc->code)) {
+ /* Should change type to closure here */
+ s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
+ sc->args = sc->NIL;
+ s_goto(sc,OP_APPLY);
+ } else {
+ s_return(sc,sc->code);
+ }
+
+ case OP_SAVE_FORCED: /* Save forced value replacing promise */
+ memcpy(sc->code,sc->value,sizeof(struct cell));
+ s_return(sc,sc->value);
+
+ case OP_WRITE: /* write */
+ case OP_DISPLAY: /* display */
+ case OP_WRITE_CHAR: /* write-char */
+ if(is_pair(cdr(sc->args))) {
+ if(cadr(sc->args)!=sc->outport) {
+ x=cons(sc,sc->outport,sc->NIL);
+ s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
+ sc->outport=cadr(sc->args);
+ }
+ }
+ sc->args = car(sc->args);
+ if(op==OP_WRITE) {
+ sc->print_flag = 1;
+ } else {
+ sc->print_flag = 0;
+ }
+ s_goto(sc,OP_P0LIST);
+
+ case OP_NEWLINE: /* newline */
+ if(is_pair(sc->args)) {
+ if(car(sc->args)!=sc->outport) {
+ x=cons(sc,sc->outport,sc->NIL);
+ s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
+ sc->outport=car(sc->args);
+ }
+ }
+ putstr(sc, "\n");
+ s_return(sc,sc->T);
+
+ case OP_ERR0: /* error */
+ sc->retcode=-1;
+ if (!is_string(car(sc->args))) {
+ sc->args=cons(sc,mk_string(sc," -- "),sc->args);
+ setimmutable(car(sc->args));
+ }
+ putstr(sc, "Error: ");
+ putstr(sc, strvalue(car(sc->args)));
+ sc->args = cdr(sc->args);
+ s_goto(sc,OP_ERR1);
+
+ case OP_ERR1: /* error */
+ putstr(sc, " ");
+ if (sc->args != sc->NIL) {
+ s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
+ sc->args = car(sc->args);
+ sc->print_flag = 1;
+ s_goto(sc,OP_P0LIST);
+ } else {
+ putstr(sc, "\n");
+ if(sc->interactive_repl) {
+ s_goto(sc,OP_T0LVL);
+ } else {
+ return sc->NIL;
+ }
+ }
+
+ case OP_REVERSE: /* reverse */
+ s_return(sc,reverse(sc, car(sc->args)));
+
+ case OP_LIST_STAR: /* list* */
+ s_return(sc,list_star(sc,sc->args));
+
+ case OP_APPEND: /* append */
+ x = sc->NIL;
+ y = sc->args;
+ if (y == x) {
+ s_return(sc, x);
+ }
+
+ /* cdr() in the while condition is not a typo. If car() */
+ /* is used (append '() 'a) will return the wrong result.*/
+ while (cdr(y) != sc->NIL) {
+ x = revappend(sc, x, car(y));
+ y = cdr(y);
+ if (x == sc->F) {
+ Error_0(sc, "non-list argument to append");
+ }
+ }
+
+ s_return(sc, reverse_in_place(sc, car(y), x));
+
+#if USE_PLIST
+ case OP_PUT: /* put */
+ if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
+ Error_0(sc,"illegal use of put");
+ }
+ for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
+ if (caar(x) == y) {
+ break;
+ }
+ }
+ if (x != sc->NIL)
+ cdar(x) = caddr(sc->args);
+ else
+ symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
+ symprop(car(sc->args)));
+ s_return(sc,sc->T);
+
+ case OP_GET: /* get */
+ if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
+ Error_0(sc,"illegal use of get");
+ }
+ for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
+ if (caar(x) == y) {
+ break;
+ }
+ }
+ if (x != sc->NIL) {
+ s_return(sc,cdar(x));
+ } else {
+ s_return(sc,sc->NIL);
+ }
+#endif /* USE_PLIST */
+ case OP_QUIT: /* quit */
+ if(is_pair(sc->args)) {
+ sc->retcode=ivalue(car(sc->args));
+ }
+ return (sc->NIL);
+
+ case OP_GC: /* gc */
+ gc(sc, sc->NIL, sc->NIL);
+ s_return(sc,sc->T);
+
+ case OP_GCVERB: /* gc-verbose */
+ { int was = sc->gc_verbose;
+
+ sc->gc_verbose = (car(sc->args) != sc->F);
+ s_retbool(was);
+ }
+
+ case OP_NEWSEGMENT: /* new-segment */
+ if (!is_pair(sc->args) || !is_number(car(sc->args))) {
+ Error_0(sc,"new-segment: argument must be a number");
+ }
+ alloc_cellseg(sc, (int) ivalue(car(sc->args)));
+ s_return(sc,sc->T);
+
+ case OP_OBLIST: /* oblist */
+ s_return(sc, oblist_all_symbols(sc));
+
+ case OP_CURR_INPORT: /* current-input-port */
+ s_return(sc,sc->inport);
+
+ case OP_CURR_OUTPORT: /* current-output-port */
+ s_return(sc,sc->outport);
+
+ case OP_OPEN_INFILE: /* open-input-file */
+ case OP_OPEN_OUTFILE: /* open-output-file */
+ case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
+ int prop=0;
+ pointer p;
+ switch(op) {
+ case OP_OPEN_INFILE: prop=port_input; break;
+ case OP_OPEN_OUTFILE: prop=port_output; break;
+ case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
+ default: break; /* Quiet the compiler */
+ }
+ p=port_from_filename(sc,strvalue(car(sc->args)),prop);
+ if(p==sc->NIL) {
+ s_return(sc,sc->F);
+ }
+ s_return(sc,p);
+ }
+
+#if USE_STRING_PORTS
+ case OP_OPEN_INSTRING: /* open-input-string */
+ case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
+ int prop=0;
+ pointer p;
+ switch(op) {
+ case OP_OPEN_INSTRING: prop=port_input; break;
+ case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
+ default: break; /* Quiet the compiler */
+ }
+ p=port_from_string(sc, strvalue(car(sc->args)),
+ g_utf8_offset_to_pointer(strvalue(car(sc->args)),
+ strlength(car(sc->args))), prop);
+ if(p==sc->NIL) {
+ s_return(sc,sc->F);
+ }
+ s_return(sc,p);
+ }
+ case OP_OPEN_OUTSTRING: /* open-output-string */ {
+ pointer p;
+ if(car(sc->args)==sc->NIL) {
+ p=port_from_scratch(sc);
+ if(p==sc->NIL) {
+ s_return(sc,sc->F);
+ }
+ } else {
+ p=port_from_string(sc, strvalue(car(sc->args)),
+ strvalue(car(sc->args))+strlength(car(sc->args)),
+ port_output);
+ if(p==sc->NIL) {
+ s_return(sc,sc->F);
+ }
+ }
+ s_return(sc,p);
+ }
+ case OP_GET_OUTSTRING: /* get-output-string */ {
+ port *p;
+
+ if ((p=car(sc->args)->_object._port)->kind&port_string) {
+ off_t size;
+ char *str;
+
+ size=p->rep.string.curr-p->rep.string.start+1;
+ str=sc->malloc(size);
+ if(str != NULL) {
+ pointer s;
+
+ memcpy(str,p->rep.string.start,size-1);
+ str[size-1]='\0';
+ s=mk_string(sc,str);
+ sc->free(str);
+ s_return(sc,s);
+ }
+ }
+ s_return(sc,sc->F);
+ }
+#endif
+
+ case OP_CLOSE_INPORT: /* close-input-port */
+ port_close(sc,car(sc->args),port_input);
+ s_return(sc,sc->T);
+
+ case OP_CLOSE_OUTPORT: /* close-output-port */
+ port_close(sc,car(sc->args),port_output);
+ s_return(sc,sc->T);
+
+ case OP_INT_ENV: /* interaction-environment */
+ s_return(sc,sc->global_env);
+
+ case OP_CURR_ENV: /* current-environment */
+ s_return(sc,sc->envir);
+
+ default:
+ sprintf(sc->strbuff, "%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T;
+}
+
+static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
+ pointer x;
+ char *trans_str;
+
+ if(sc->nesting!=0) {
+ int n=sc->nesting;
+ sc->nesting=0;
+ sc->retcode=-1;
+ Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
+ }
+
+ switch (op) {
+ /* ========== reading part ========== */
+ case OP_READ:
+ if(!is_pair(sc->args)) {
+ s_goto(sc,OP_READ_INTERNAL);
+ }
+ if(!is_inport(car(sc->args))) {
+ Error_1(sc,"read: not an input port:",car(sc->args));
+ }
+ if(car(sc->args)==sc->inport) {
+ s_goto(sc,OP_READ_INTERNAL);
+ }
+ x=sc->inport;
+ sc->inport=car(sc->args);
+ x=cons(sc,x,sc->NIL);
+ s_save(sc,OP_SET_INPORT, x, sc->NIL);
+ s_goto(sc,OP_READ_INTERNAL);
+
+ case OP_READ_CHAR: /* read-char */
+ case OP_PEEK_CHAR: /* peek-char */ {
+ gunichar c;
+ if(is_pair(sc->args)) {
+ if(car(sc->args)!=sc->inport) {
+ x=sc->inport;
+ x=cons(sc,x,sc->NIL);
+ s_save(sc,OP_SET_INPORT, x, sc->NIL);
+ sc->inport=car(sc->args);
+ }
+ }
+ c=inchar(sc);
+ if(c==EOF) {
+ s_return(sc,sc->EOF_OBJ);
+ }
+ if(sc->op==OP_PEEK_CHAR) {
+ backchar(sc,c);
+ }
+ s_return(sc,mk_character(sc,c));
+ }
+
+ case OP_CHAR_READY: /* char-ready? */ {
+ pointer p=sc->inport;
+ int res;
+ if(is_pair(sc->args)) {
+ p=car(sc->args);
+ }
+ res=p->_object._port->kind&port_string;
+ s_retbool(res);
+ }
+
+ case OP_SET_INPORT: /* set-input-port */
+ sc->inport=car(sc->args);
+ s_return(sc,sc->value);
+
+ case OP_SET_OUTPORT: /* set-output-port */
+ sc->outport=car(sc->args);
+ s_return(sc,sc->value);
+
+ case OP_RDSEXPR:
+ switch (sc->tok) {
+ case TOK_EOF:
+ s_return(sc,sc->EOF_OBJ);
+ /* NOTREACHED */
+/*
+ * Commented out because we now skip comments in the scanner
+ *
+ case TOK_COMMENT: {
+ gunichar c;
+ while ((c=inchar(sc)) != '\n' && c!=EOF)
+ ;
+ sc->tok = token(sc);
+ s_goto(sc,OP_RDSEXPR);
+ }
+*/
+ case TOK_VEC:
+ s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
+ /* fall through */
+ case TOK_LPAREN:
+ sc->tok = token(sc);
+ if (sc->tok == TOK_RPAREN) {
+ s_return(sc,sc->NIL);
+ } else if (sc->tok == TOK_DOT) {
+ Error_0(sc,"syntax error: illegal dot expression");
+ } else {
+ sc->nesting_stack[sc->file_i]++;
+ s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
+ s_goto(sc,OP_RDSEXPR);
+ }
+ case TOK_QUOTE:
+ s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
+ sc->tok = token(sc);
+ s_goto(sc,OP_RDSEXPR);
+ case TOK_BQUOTE:
+ sc->tok = token(sc);
+ if(sc->tok==TOK_VEC) {
+ s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
+ sc->tok=TOK_LPAREN;
+ s_goto(sc,OP_RDSEXPR);
+ } else {
+ s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
+ }
+ s_goto(sc,OP_RDSEXPR);
+ case TOK_COMMA:
+ s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
+ sc->tok = token(sc);
+ s_goto(sc,OP_RDSEXPR);
+ case TOK_ATMARK:
+ s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
+ sc->tok = token(sc);
+ s_goto(sc,OP_RDSEXPR);
+ case TOK_ATOM:
+ s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
+ case TOK_DQUOTE:
+ x=readstrexp(sc);
+ if(x==sc->F) {
+ Error_0(sc,"Error reading string");
+ }
+ setimmutable(x);
+ s_return(sc,x);
+ case TOK_USCORE:
+ x=readstrexp(sc);
+ if(x==sc->F) {
+ Error_0(sc,"Error reading string");
+ }
+ trans_str = gettext (strvalue (x));
+ if (trans_str != strvalue(x)) {
+ sc->free(strvalue(x));
+ strlength(x) = g_utf8_strlen(trans_str, -1);
+ strvalue(x) = store_string(sc, strlength(x), trans_str, 0);
+ }
+ setimmutable(x);
+ s_return(sc,x);
+ case TOK_SHARP: {
+ pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
+ if(f==sc->NIL) {
+ Error_0(sc,"undefined sharp expression");
+ } else {
+ sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
+ s_goto(sc,OP_EVAL);
+ }
+ }
+ case TOK_SHARP_CONST:
+ if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
+ Error_0(sc,"undefined sharp expression");
+ } else {
+ s_return(sc,x);
+ }
+ default:
+ Error_1(sc, "syntax error: illegal token", mk_integer (sc, sc->tok));
+ }
+ break;
+
+ case OP_RDLIST: {
+ sc->args = cons(sc, sc->value, sc->args);
+ sc->tok = token(sc);
+/* We now skip comments in the scanner
+ while (sc->tok == TOK_COMMENT) {
+ gunichar c;
+ while ((c=inchar(sc)) != '\n' && c!=EOF)
+ ;
+ sc->tok = token(sc);
+ }
+*/
+ if (sc->tok == TOK_EOF)
+ { s_return(sc,sc->EOF_OBJ); }
+ else if (sc->tok == TOK_RPAREN) {
+ gunichar c = inchar(sc);
+ if (c != '\n')
+ backchar(sc,c);
+#if SHOW_ERROR_LINE
+ else if (sc->load_stack[sc->file_i].kind & port_file)
+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
+#endif
+ sc->nesting_stack[sc->file_i]--;
+ s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
+ } else if (sc->tok == TOK_DOT) {
+ s_save(sc,OP_RDDOT, sc->args, sc->NIL);
+ sc->tok = token(sc);
+ s_goto(sc,OP_RDSEXPR);
+ } else {
+ s_save(sc,OP_RDLIST, sc->args, sc->NIL);
+ s_goto(sc,OP_RDSEXPR);
+ }
+ }
+
+ case OP_RDDOT:
+ if (token(sc) != TOK_RPAREN) {
+ Error_0(sc,"syntax error: illegal dot expression");
+ } else {
+ sc->nesting_stack[sc->file_i]--;
+ s_return(sc,reverse_in_place(sc, sc->value, sc->args));
+ }
+
+ case OP_RDQUOTE:
+ s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
+
+ case OP_RDQQUOTE:
+ s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
+
+ case OP_RDQQUOTEVEC:
+ s_return(sc,cons(sc, mk_symbol(sc,"apply"),
+ cons(sc, mk_symbol(sc,"vector"),
+ cons(sc,cons(sc, sc->QQUOTE,
+ cons(sc,sc->value,sc->NIL)),
+ sc->NIL))));
+
+ case OP_RDUNQUOTE:
+ s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
+
+ case OP_RDUQTSP:
+ s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
+
+ case OP_RDVEC:
+ /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
+ s_goto(sc,OP_EVAL); Cannot be quoted*/
+ /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
+ s_return(sc,x); Cannot be part of pairs*/
+ /*sc->code=mk_proc(sc,OP_VECTOR);
+ sc->args=sc->value;
+ s_goto(sc,OP_APPLY);*/
+ sc->args=sc->value;
+ s_goto(sc,OP_VECTOR);
+
+ /* ========== printing part ========== */
+ case OP_P0LIST:
+ if(is_vector(sc->args)) {
+ putstr(sc,"#(");
+ sc->args=cons(sc,sc->args,mk_integer(sc,0));
+ s_goto(sc,OP_PVECFROM);
+ } else if(is_environment(sc->args)) {
+ putstr(sc,"#<ENVIRONMENT>");
+ s_return(sc,sc->T);
+ } else if (!is_pair(sc->args)) {
+ printatom(sc, sc->args, sc->print_flag);
+ s_return(sc,sc->T);
+ } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
+ putstr(sc, "'");
+ sc->args = cadr(sc->args);
+ s_goto(sc,OP_P0LIST);
+ } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
+ putstr(sc, "`");
+ sc->args = cadr(sc->args);
+ s_goto(sc,OP_P0LIST);
+ } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
+ putstr(sc, ",");
+ sc->args = cadr(sc->args);
+ s_goto(sc,OP_P0LIST);
+ } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
+ putstr(sc, ",@");
+ sc->args = cadr(sc->args);
+ s_goto(sc,OP_P0LIST);
+ } else {
+ putstr(sc, "(");
+ s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
+ sc->args = car(sc->args);
+ s_goto(sc,OP_P0LIST);
+ }
+
+ case OP_P1LIST:
+ if (is_pair(sc->args)) {
+ s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
+ putstr(sc, " ");
+ sc->args = car(sc->args);
+ s_goto(sc,OP_P0LIST);
+ } else if(is_vector(sc->args)) {
+ s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
+ putstr(sc, " . ");
+ s_goto(sc,OP_P0LIST);
+ } else {
+ if (sc->args != sc->NIL) {
+ putstr(sc, " . ");
+ printatom(sc, sc->args, sc->print_flag);
+ }
+ putstr(sc, ")");
+ s_return(sc,sc->T);
+ }
+ case OP_PVECFROM: {
+ int i=ivalue_unchecked(cdr(sc->args));
+ pointer vec=car(sc->args);
+ int len=ivalue_unchecked(vec);
+ if(i==len) {
+ putstr(sc,")");
+ s_return(sc,sc->T);
+ } else {
+ pointer elem=vector_elem(vec,i);
+ ivalue_unchecked(cdr(sc->args))=i+1;
+ s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
+ sc->args=elem;
+ if (i > 0)
+ putstr(sc," ");
+ s_goto(sc,OP_P0LIST);
+ }
+ }
+
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+
+ }
+ return sc->T;
+}
+
+static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
+ pointer x, y;
+ long v;
+
+ switch (op) {
+ case OP_LIST_LENGTH: /* length */ /* a.k */
+ v=list_length(sc,car(sc->args));
+ if(v<0) {
+ Error_1(sc,"length: not a list:",car(sc->args));
+ }
+ s_return(sc,mk_integer(sc, v));
+
+ case OP_ASSQ: /* assq */ /* a.k */
+ x = car(sc->args);
+ for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
+ if (!is_pair(car(y))) {
+ Error_0(sc,"unable to handle non pair element");
+ }
+ if (x == caar(y))
+ break;
+ }
+ if (is_pair(y)) {
+ s_return(sc,car(y));
+ } else {
+ s_return(sc,sc->F);
+ }
+
+
+ case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
+ sc->args = car(sc->args);
+ if (sc->args == sc->NIL) {
+ s_return(sc,sc->F);
+ } else if (is_closure(sc->args)) {
+ s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
+ } else if (is_macro(sc->args)) {
+ s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
+ } else {
+ s_return(sc,sc->F);
+ }
+ case OP_CLOSUREP: /* closure? */
+ /*
+ * Note, macro object is also a closure.
+ * Therefore, (closure? <#MACRO>) ==> #t
+ */
+ s_retbool(is_closure(car(sc->args)));
+ case OP_MACROP: /* macro? */
+ s_retbool(is_macro(car(sc->args)));
+ default:
+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
+ Error_0(sc,sc->strbuff);
+ }
+ return sc->T; /* NOTREACHED */
+}
+
+typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
+
+typedef int (*test_predicate)(pointer);
+static int is_any(pointer p) { return 1;}
+
+static int is_nonneg(pointer p) {
+ return ivalue(p)>=0 && is_integer(p);
+}
+
+/* Correspond carefully with following defines! */
+static struct {
+ test_predicate fct;
+ const char *kind;
+} tests[]={
+ {0,0}, /* unused */
+ {is_any, 0},
+ {is_string, "string"},
+ {is_symbol, "symbol"},
+ {is_port, "port"},
+ {is_inport,"input port"},
+ {is_outport,"output port"},
+ {is_environment, "environment"},
+ {is_pair, "pair"},
+ {0, "pair or '()"},
+ {is_character, "character"},
+ {is_vector, "vector"},
+ {is_number, "number"},
+ {is_integer, "integer"},
+ {is_nonneg, "non-negative integer"}
+};
+
+#define TST_NONE 0
+#define TST_ANY "\001"
+#define TST_STRING "\002"
+#define TST_SYMBOL "\003"
+#define TST_PORT "\004"
+#define TST_INPORT "\005"
+#define TST_OUTPORT "\006"
+#define TST_ENVIRONMENT "\007"
+#define TST_PAIR "\010"
+#define TST_LIST "\011"
+#define TST_CHAR "\012"
+#define TST_VECTOR "\013"
+#define TST_NUMBER "\014"
+#define TST_INTEGER "\015"
+#define TST_NATURAL "\016"
+
+typedef struct {
+ dispatch_func func;
+ char *name;
+ int min_arity;
+ int max_arity;
+ char *arg_tests_encoding;
+} op_code_info;
+
+#define INF_ARG 0xffff
+
+static op_code_info dispatch_table[]= {
+#define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
+#include "opdefines.h"
+ { 0 }
+};
+
+static const char *procname(pointer x) {
+ int n=procnum(x);
+ const char *name=dispatch_table[n].name;
+ if(name==0) {
+ name="ILLEGAL!";
+ }
+ return name;
+}
+
+/* kernel of this interpreter */
+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
+ sc->op = op;
+ for (;;) {
+ op_code_info *pcd=dispatch_table+sc->op;
+ if (pcd->name!=0) { /* if built-in function, check arguments */
+ char msg[STRBUFFSIZE];
+ int ok=1;
+ int n=list_length(sc,sc->args);
+
+ /* Check number of arguments */
+ if(n<pcd->min_arity) {
+ ok=0;
+ snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
+ pcd->name,
+ pcd->min_arity==pcd->max_arity?"":" at least",
+ pcd->min_arity);
+ }
+ if(ok && n>pcd->max_arity) {
+ ok=0;
+ snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
+ pcd->name,
+ pcd->min_arity==pcd->max_arity?"":" at most",
+ pcd->max_arity);
+ }
+ if(ok) {
+ if(pcd->arg_tests_encoding!=0) {
+ int i=0;
+ int j;
+ const char *t=pcd->arg_tests_encoding;
+ pointer arglist=sc->args;
+ do {
+ pointer arg=car(arglist);
+ j=(int)t[0];
+ if(j==TST_LIST[0]) {
+ if(arg!=sc->NIL && !is_pair(arg)) break;
+ } else {
+ if(!tests[j].fct(arg)) break;
+ }
+
+ if(t[1]!=0) {/* last test is replicated as necessary */
+ t++;
+ }
+ arglist=cdr(arglist);
+ i++;
+ } while(i<n);
+ if(i<n) {
+ ok=0;
+ snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s",
+ pcd->name,
+ i+1,
+ tests[j].kind);
+ }
+ }
+ }
+ if(!ok) {
+ if(_Error_1(sc,msg,0)==sc->NIL) {
+ return;
+ }
+ pcd=dispatch_table+sc->op;
+ }
+ }
+ ok_to_freely_gc(sc);
+ if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
+ return;
+ }
+ if(sc->no_memory) {
+ fprintf(stderr,"No memory!\n");
+ return;
+ }
+ }
+}
+
+/* ========== Initialization of internal keywords ========== */
+
+static void assign_syntax(scheme *sc, char *name) {
+ pointer x;
+
+ x = oblist_add_by_name(sc, name);
+ typeflag(x) |= T_SYNTAX;
+}
+
+static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
+ pointer x, y;
+
+ x = mk_symbol(sc, name);
+ y = mk_proc(sc,op);
+ new_slot_in_env(sc, x, y);
+}
+
+static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
+ pointer y;
+
+ y = get_cell(sc, sc->NIL, sc->NIL);
+ typeflag(y) = (T_PROC | T_ATOM);
+ ivalue_unchecked(y) = (long) op;
+ set_num_integer(y);
+ return y;
+}
+
+/* Hard-coded for the given keywords. Remember to rewrite if more are added! */
+static int syntaxnum(pointer p) {
+ const char *s=strvalue(car(p));
+ switch(strlength(car(p))) {
+ case 2:
+ if(s[0]=='i') return OP_IF0; /* if */
+ else return OP_OR0; /* or */
+ case 3:
+ if(s[0]=='a') return OP_AND0; /* and */
+ else return OP_LET0; /* let */
+ case 4:
+ switch(s[3]) {
+ case 'e': return OP_CASE0; /* case */
+ case 'd': return OP_COND0; /* cond */
+ case '*': return OP_LET0AST; /* let* */
+ default: return OP_SET0; /* set! */
+ }
+ case 5:
+ switch(s[2]) {
+ case 'g': return OP_BEGIN; /* begin */
+ case 'l': return OP_DELAY; /* delay */
+ case 'c': return OP_MACRO0; /* macro */
+ default: return OP_QUOTE; /* quote */
+ }
+ case 6:
+ switch(s[2]) {
+ case 'm': return OP_LAMBDA; /* lambda */
+ case 'f': return OP_DEF0; /* define */
+ default: return OP_LET0REC; /* letrec */
+ }
+ default:
+ return OP_C0STREAM; /* cons-stream */
+ }
+}
+
+/* initialization of TinyScheme */
+#if USE_INTERFACE
+INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
+ return cons(sc,a,b);
+}
+INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
+ return immutable_cons(sc,a,b);
+}
+
+static struct scheme_interface vtbl ={
+ scheme_define,
+ s_cons,
+ s_immutable_cons,
+ reserve_cells,
+ mk_integer,
+ mk_real,
+ mk_symbol,
+ gensym,
+ mk_string,
+ mk_counted_string,
+ mk_character,
+ mk_vector,
+ mk_foreign_func,
+ mk_closure,
+ putstr,
+ putcharacter,
+
+ is_string,
+ string_length,
+ string_value,
+ is_number,
+ nvalue,
+ ivalue,
+ rvalue,
+ is_integer,
+ is_real,
+ is_character,
+ charvalue,
+ is_list,
+ is_vector,
+ list_length,
+ ivalue,
+ fill_vector,
+ vector_elem,
+ set_vector_elem,
+ is_port,
+ is_pair,
+ pair_car,
+ pair_cdr,
+ set_car,
+ set_cdr,
+
+ is_symbol,
+ symname,
+
+ is_syntax,
+ is_proc,
+ is_foreign,
+ syntaxname,
+ is_closure,
+ is_macro,
+ closure_code,
+ closure_env,
+
+ is_continuation,
+ is_promise,
+ is_environment,
+ is_immutable,
+ setimmutable,
+
+ scheme_load_file,
+ scheme_load_string
+};
+#endif
+
+scheme *scheme_init_new(void) {
+ scheme *sc=(scheme*)malloc(sizeof(scheme));
+ if(!scheme_init(sc)) {
+ free(sc);
+ return 0;
+ } else {
+ return sc;
+ }
+}
+
+scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
+ scheme *sc=(scheme*)malloc(sizeof(scheme));
+ if(!scheme_init_custom_alloc(sc,malloc,free)) {
+ free(sc);
+ return 0;
+ } else {
+ return sc;
+ }
+}
+
+
+int scheme_init(scheme *sc) {
+ return scheme_init_custom_alloc(sc,malloc,free);
+}
+
+int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
+ int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
+ pointer x;
+
+ num_zero.is_fixnum=1;
+ num_zero.value.ivalue=0;
+ num_one.is_fixnum=1;
+ num_one.value.ivalue=1;
+
+#if USE_INTERFACE
+ sc->vptr=&vtbl;
+#endif
+ sc->gensym_cnt=0;
+ sc->malloc=malloc;
+ sc->free=free;
+ sc->last_cell_seg = -1;
+ sc->sink = &sc->_sink;
+ sc->NIL = &sc->_NIL;
+ sc->T = &sc->_HASHT;
+ sc->F = &sc->_HASHF;
+ sc->EOF_OBJ=&sc->_EOF_OBJ;
+ sc->free_cell = &sc->_NIL;
+ sc->fcells = 0;
+ sc->no_memory=0;
+ sc->inport=sc->NIL;
+ sc->outport=sc->NIL;
+ sc->save_inport=sc->NIL;
+ sc->loadport=sc->NIL;
+ sc->nesting=0;
+ sc->interactive_repl=0;
+ sc->print_output=0;
+
+ if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
+ sc->no_memory=1;
+ return 0;
+ }
+ sc->gc_verbose = 0;
+ dump_stack_initialize(sc);
+ sc->code = sc->NIL;
+ sc->tracing=0;
+ sc->bc_flag = 0;
+
+ /* init sc->NIL */
+ typeflag(sc->NIL) = (T_ATOM | MARK);
+ car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
+ /* init T */
+ typeflag(sc->T) = (T_ATOM | MARK);
+ car(sc->T) = cdr(sc->T) = sc->T;
+ /* init F */
+ typeflag(sc->F) = (T_ATOM | MARK);
+ car(sc->F) = cdr(sc->F) = sc->F;
+ /* init sink */
+ typeflag(sc->sink) = (T_PAIR | MARK);
+ car(sc->sink) = sc->NIL;
+ /* init c_nest */
+ sc->c_nest = sc->NIL;
+
+ sc->oblist = oblist_initial_value(sc);
+ /* init global_env */
+ new_frame_in_env(sc, sc->NIL);
+ sc->global_env = sc->envir;
+ /* init else */
+ x = mk_symbol(sc,"else");
+ new_slot_in_env(sc, x, sc->T);
+
+ assign_syntax(sc, "lambda");
+ assign_syntax(sc, "quote");
+ assign_syntax(sc, "define");
+ assign_syntax(sc, "if");
+ assign_syntax(sc, "begin");
+ assign_syntax(sc, "set!");
+ assign_syntax(sc, "let");
+ assign_syntax(sc, "let*");
+ assign_syntax(sc, "letrec");
+ assign_syntax(sc, "cond");
+ assign_syntax(sc, "delay");
+ assign_syntax(sc, "and");
+ assign_syntax(sc, "or");
+ assign_syntax(sc, "cons-stream");
+ assign_syntax(sc, "macro");
+ assign_syntax(sc, "case");
+
+ for(i=0; i<n; i++) {
+ if(dispatch_table[i].name!=0) {
+ assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
+ }
+ }
+
+ /* initialization of global pointers to special symbols */
+ sc->LAMBDA = mk_symbol(sc, "lambda");
+ sc->QUOTE = mk_symbol(sc, "quote");
+ sc->QQUOTE = mk_symbol(sc, "quasiquote");
+ sc->UNQUOTE = mk_symbol(sc, "unquote");
+ sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
+ sc->FEED_TO = mk_symbol(sc, "=>");
+ sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
+ sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
+ sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
+ sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
+
+ return !sc->no_memory;
+}
+
+SCHEME_EXPORT void scheme_set_input_port_file(scheme *sc, FILE *fin) {
+ sc->inport=port_from_file(sc,fin,port_input);
+}
+
+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
+ sc->inport=port_from_string(sc,start,past_the_end,port_input);
+}
+
+SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fout) {
+ sc->outport=port_from_file(sc,fout,port_output);
+}
+
+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
+ sc->outport=port_from_string(sc,start,past_the_end,port_output);
+}
+
+void scheme_set_external_data(scheme *sc, void *p) {
+ sc->ext_data=p;
+}
+
+void scheme_deinit(scheme *sc) {
+ int i;
+
+#if SHOW_ERROR_LINE
+ char *fname;
+#endif
+
+ sc->oblist=sc->NIL;
+ sc->global_env=sc->NIL;
+ dump_stack_free(sc);
+ sc->envir=sc->NIL;
+ sc->code=sc->NIL;
+ sc->args=sc->NIL;
+ sc->value=sc->NIL;
+ if(is_port(sc->inport)) {
+ typeflag(sc->inport) = T_ATOM;
+ }
+ sc->inport=sc->NIL;
+ sc->outport=sc->NIL;
+ if(is_port(sc->save_inport)) {
+ typeflag(sc->save_inport) = T_ATOM;
+ }
+ sc->save_inport=sc->NIL;
+ if(is_port(sc->loadport)) {
+ typeflag(sc->loadport) = T_ATOM;
+ }
+ sc->loadport=sc->NIL;
+ sc->gc_verbose=0;
+ gc(sc,sc->NIL,sc->NIL);
+
+ for(i=0; i<=sc->last_cell_seg; i++) {
+ sc->free(sc->alloc_seg[i]);
+ }
+
+#if SHOW_ERROR_LINE
+ for(i=0; i<sc->file_i; i++) {
+ if (sc->load_stack[sc->file_i].kind & port_file) {
+ fname = sc->load_stack[i].rep.stdio.filename;
+ if(fname)
+ sc->free(fname);
+ }
+ }
+#endif
+}
+
+void scheme_load_file(scheme *sc, FILE *fin)
+{ scheme_load_named_file(sc,fin,0); }
+
+void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
+ dump_stack_reset(sc);
+ sc->envir = sc->global_env;
+ sc->file_i=0;
+ sc->load_stack[0].kind=port_input|port_file;
+ sc->load_stack[0].rep.stdio.file=fin;
+ sc->loadport=mk_port(sc,sc->load_stack);
+ sc->retcode=0;
+ if(fin==stdin) {
+ sc->interactive_repl=1;
+ }
+
+#if SHOW_ERROR_LINE
+ sc->load_stack[0].rep.stdio.curr_line = 0;
+ if(fin!=stdin && filename)
+ sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
+ else
+ sc->load_stack[0].rep.stdio.filename = NULL;
+#endif
+
+ sc->inport=sc->loadport;
+ sc->args = mk_integer(sc,sc->file_i);
+ Eval_Cycle(sc, OP_T0LVL);
+ typeflag(sc->loadport)=T_ATOM;
+ if(sc->retcode==0) {
+ sc->retcode=sc->nesting!=0;
+ }
+}
+
+void scheme_load_string(scheme *sc, const char *cmd) {
+ dump_stack_reset(sc);
+ sc->envir = sc->global_env;
+ sc->file_i=0;
+ sc->load_stack[0].kind=port_input|port_string;
+ sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
+ sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
+ sc->load_stack[0].rep.string.curr=(char*)cmd;
+ sc->loadport=mk_port(sc,sc->load_stack);
+ sc->retcode=0;
+ sc->interactive_repl=0;
+ sc->inport=sc->loadport;
+ sc->args = mk_integer(sc,sc->file_i);
+ Eval_Cycle(sc, OP_T0LVL);
+ typeflag(sc->loadport)=T_ATOM;
+ if(sc->retcode==0) {
+ sc->retcode=sc->nesting!=0;
+ }
+}
+
+void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
+ pointer x;
+
+ x=find_slot_in_env(sc,envir,symbol,0);
+ if (x != sc->NIL) {
+ set_slot_in_env(sc, x, value);
+ } else {
+ new_slot_spec_in_env(sc, envir, symbol, value);
+ }
+}
+
+#if !STANDALONE
+void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
+{
+ scheme_define(sc,
+ sc->global_env,
+ mk_symbol(sc,sr->name),
+ mk_foreign_func(sc, sr->f));
+}
+
+void scheme_register_foreign_func_list(scheme * sc,
+ scheme_registerable * list,
+ int count)
+{
+ int i;
+ for(i = 0; i < count; i++)
+ {
+ scheme_register_foreign_func(sc, list + i);
+ }
+}
+
+pointer scheme_apply0(scheme *sc, const char *procname)
+{ return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
+
+static void save_from_C_call(scheme *sc)
+{
+ pointer saved_data =
+ cons(sc,
+ car(sc->sink),
+ cons(sc,
+ sc->envir,
+ sc->dump));
+ /* Push */
+ sc->c_nest = cons(sc, saved_data, sc->c_nest);
+ /* Truncate the dump stack so TS will return here when done, not
+ directly resume pre-C-call operations. */
+ dump_stack_reset(sc);
+}
+
+static void restore_from_C_call(scheme *sc)
+{
+ car(sc->sink) = caar(sc->c_nest);
+ sc->envir = cadar(sc->c_nest);
+ sc->dump = cdr(cdar(sc->c_nest));
+ /* Pop */
+ sc->c_nest = cdr(sc->c_nest);
+}
+
+/* "func" and "args" are assumed to be already eval'ed. */
+pointer scheme_call(scheme *sc, pointer func, pointer args)
+{
+ int old_repl = sc->interactive_repl;
+ sc->interactive_repl = 0;
+ save_from_C_call(sc);
+ sc->envir = sc->global_env;
+ sc->args = args;
+ sc->code = func;
+ sc->retcode = 0;
+ Eval_Cycle(sc, OP_APPLY);
+ sc->interactive_repl = old_repl;
+ restore_from_C_call(sc);
+ return sc->value;
+}
+
+pointer scheme_eval(scheme *sc, pointer obj)
+{
+ int old_repl = sc->interactive_repl;
+ sc->interactive_repl = 0;
+ save_from_C_call(sc);
+ sc->args = sc->NIL;
+ sc->code = obj;
+ sc->retcode = 0;
+ Eval_Cycle(sc, OP_EVAL);
+ sc->interactive_repl = old_repl;
+ restore_from_C_call(sc);
+ return sc->value;
+}
+
+
+#endif
+
+/* ========== Main ========== */
+
+#if STANDALONE
+
+#if defined(__APPLE__) && !defined (OSX)
+int main(int argc, char **argv)
+{
+ extern MacTS_main(int argc, char **argv);
+ char** argv;
+ int argc = ccommand(&argv);
+ MacTS_main(argc,argv);
+ return 0;
+}
+int MacTS_main(int argc, char **argv) {
+#else
+int main(int argc, char **argv) {
+#endif
+ scheme sc;
+ FILE *fin;
+ char *file_name=InitFile;
+ int retcode;
+ int isfile=1;
+
+ if(argc==1) {
+ printf(banner);
+ }
+ if(argc==2 && strcmp(argv[1],"-?")==0) {
+ printf("Usage: tinyscheme -?\n");
+ printf("or: tinyscheme [<file1> <file2> ...]\n");
+ printf("followed by\n");
+ printf(" -1 <file> [<arg1> <arg2> ...]\n");
+ printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
+ printf("assuming that the executable is named tinyscheme.\n");
+ printf("Use - as filename for stdin.\n");
+ return 1;
+ }
+ if(!scheme_init(&sc)) {
+ fprintf(stderr,"Could not initialize!\n");
+ return 2;
+ }
+ scheme_set_input_port_file(&sc, stdin);
+ scheme_set_output_port_file(&sc, stdout);
+#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;
+ }
+ }
+ do {
+ if(strcmp(file_name,"-")==0) {
+ fin=stdin;
+ } 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");
+ }
+ for(;*argv;argv++) {
+ pointer value=mk_string(&sc,*argv);
+ args=cons(&sc,value,args);
+ }
+ args=reverse_in_place(&sc,sc.NIL,args);
+ scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
+
+ } else {
+ fin=g_fopen(file_name,"r");
+ }
+ if(isfile && fin==0) {
+ fprintf(stderr,"Could not open file %s\n",file_name);
+ } else {
+ if(isfile) {
+ scheme_load_named_file(&sc,fin,file_name);
+ } else {
+ scheme_load_string(&sc,file_name);
+ }
+ if(!isfile || fin!=stdin) {
+ if(sc.retcode!=0) {
+ fprintf(stderr,"Errors encountered reading %s\n",file_name);
+ }
+ if(isfile) {
+ fclose(fin);
+ }
+ }
+ }
+ file_name=*argv++;
+ } while(file_name!=0);
+ if(argc==1) {
+ scheme_load_named_file(&sc,stdin,0);
+ }
+ retcode=sc.retcode;
+ scheme_deinit(&sc);
+
+ return retcode;
+}
+
+#endif
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/
diff --git a/plug-ins/script-fu/tinyscheme/scheme.h b/plug-ins/script-fu/tinyscheme/scheme.h
new file mode 100644
index 0000000..198182c
--- /dev/null
+++ b/plug-ins/script-fu/tinyscheme/scheme.h
@@ -0,0 +1,273 @@
+/* SCHEME.H */
+
+#ifndef _SCHEME_H
+#define _SCHEME_H
+
+#include <stdio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Default values for #define'd symbols
+ */
+#ifndef STANDALONE /* If used as standalone interpreter */
+# define STANDALONE 1
+#endif
+
+#ifndef _MSC_VER
+# ifndef USE_STRLWR
+# define USE_STRLWR 1
+# endif
+# define SCHEME_EXPORT extern
+#else
+# define USE_STRLWR 0
+# ifdef _SCHEME_SOURCE
+# define SCHEME_EXPORT __declspec(dllexport)
+# else
+# define SCHEME_EXPORT __declspec(dllimport)
+# endif
+#endif
+
+#if USE_NO_FEATURES
+# define USE_MATH 0
+# define USE_CHAR_CLASSIFIERS 0
+# define USE_ASCII_NAMES 0
+# define USE_STRING_PORTS 0
+# define USE_ERROR_HOOK 0
+# define USE_TRACING 0
+# define USE_COLON_HOOK 0
+# define USE_DL 0
+# define USE_PLIST 0
+#endif
+
+/*
+ * Leave it defined if you want continuations, and also for the Sharp Zaurus.
+ * Undefine it if you only care about faster speed and not strict Scheme compatibility.
+ */
+#define USE_SCHEME_STACK
+
+#if USE_DL
+# define USE_INTERFACE 1
+#endif
+
+
+#ifndef USE_MATH /* If math support is needed */
+# define USE_MATH 1
+#endif
+
+#ifndef USE_CHAR_CLASSIFIERS /* If char classifiers are needed */
+# define USE_CHAR_CLASSIFIERS 1
+#endif
+
+#ifndef USE_ASCII_NAMES /* If extended escaped characters are needed */
+# define USE_ASCII_NAMES 1
+#endif
+
+#ifndef USE_STRING_PORTS /* Enable string ports */
+# define USE_STRING_PORTS 1
+#endif
+
+#ifndef USE_TRACING
+# define USE_TRACING 1
+#endif
+
+#ifndef USE_PLIST
+# define USE_PLIST 0
+#endif
+
+/* To force system errors through user-defined error handling (see *error-hook*) */
+#ifndef USE_ERROR_HOOK
+# define USE_ERROR_HOOK 1
+#endif
+
+#ifndef USE_COLON_HOOK /* Enable qualified qualifier */
+# define USE_COLON_HOOK 1
+#endif
+
+#ifndef USE_STRLWR
+# define USE_STRLWR 1
+#endif
+
+#ifndef STDIO_ADDS_CR /* Define if DOS/Windows */
+# define STDIO_ADDS_CR 0
+#endif
+
+#ifndef INLINE
+# define INLINE
+#endif
+
+#ifndef USE_INTERFACE
+# define USE_INTERFACE 0
+#endif
+
+#ifndef SHOW_ERROR_LINE /* Show error line in file */
+# define SHOW_ERROR_LINE 1
+#endif
+
+typedef struct scheme scheme;
+typedef struct cell *pointer;
+
+typedef void * (*func_alloc)(size_t);
+typedef void (*func_dealloc)(void *);
+
+/* num, for generic arithmetic */
+typedef struct num {
+ char is_fixnum;
+ union {
+ long ivalue;
+ double rvalue;
+ } value;
+} num;
+
+#if !STANDALONE
+
+typedef enum { TS_OUTPUT_NORMAL, TS_OUTPUT_ERROR } TsOutputType;
+
+typedef void (* ts_output_func) (TsOutputType type,
+ const char *string,
+ int len,
+ gpointer data);
+
+SCHEME_EXPORT void ts_register_output_func (ts_output_func func,
+ gpointer user_data);
+SCHEME_EXPORT void ts_output_string (TsOutputType type,
+ const char *string,
+ int len);
+#endif
+
+SCHEME_EXPORT scheme *scheme_init_new(void);
+SCHEME_EXPORT scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free);
+SCHEME_EXPORT int scheme_init(scheme *sc);
+SCHEME_EXPORT int scheme_init_custom_alloc(scheme *sc, func_alloc, func_dealloc);
+SCHEME_EXPORT void scheme_deinit(scheme *sc);
+SCHEME_EXPORT void scheme_set_input_port_file(scheme *sc, FILE *fin);
+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end);
+SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fin);
+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end);
+SCHEME_EXPORT void scheme_load_file(scheme *sc, FILE *fin);
+SCHEME_EXPORT void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename);
+SCHEME_EXPORT void scheme_load_string(scheme *sc, const char *cmd);
+SCHEME_EXPORT pointer scheme_apply0(scheme *sc, const char *procname);
+SCHEME_EXPORT pointer scheme_call(scheme *sc, pointer func, pointer args);
+SCHEME_EXPORT pointer scheme_eval(scheme *sc, pointer obj);
+void scheme_set_external_data(scheme *sc, void *p);
+SCHEME_EXPORT void scheme_define(scheme *sc, pointer env, pointer symbol, pointer value);
+
+typedef pointer (*foreign_func)(scheme *, pointer);
+
+pointer _cons(scheme *sc, pointer a, pointer b, int immutable);
+pointer mk_integer(scheme *sc, long num);
+pointer mk_real(scheme *sc, double num);
+pointer mk_symbol(scheme *sc, const char *name);
+pointer gensym(scheme *sc);
+pointer mk_string(scheme *sc, const char *str);
+pointer mk_counted_string(scheme *sc, const char *str, int len);
+pointer mk_empty_string(scheme *sc, int len, gunichar fill);
+pointer mk_character(scheme *sc, gunichar c);
+pointer mk_foreign_func(scheme *sc, foreign_func f);
+void putcharacter(scheme *sc, gunichar c);
+void putstr(scheme *sc, const char *s);
+int list_length(scheme *sc, pointer a);
+int eqv(pointer a, pointer b);
+
+SCHEME_EXPORT pointer foreign_error (scheme *sc, const char *s, pointer a);
+
+#if USE_INTERFACE
+struct scheme_interface {
+ void (*scheme_define)(scheme *sc, pointer env, pointer symbol, pointer value);
+ pointer (*cons)(scheme *sc, pointer a, pointer b);
+ pointer (*immutable_cons)(scheme *sc, pointer a, pointer b);
+ pointer (*reserve_cells)(scheme *sc, int n);
+ pointer (*mk_integer)(scheme *sc, long num);
+ pointer (*mk_real)(scheme *sc, double num);
+ pointer (*mk_symbol)(scheme *sc, const char *name);
+ pointer (*gensym)(scheme *sc);
+ pointer (*mk_string)(scheme *sc, const char *str);
+ pointer (*mk_counted_string)(scheme *sc, const char *str, int len);
+ pointer (*mk_character)(scheme *sc, gunichar c);
+ pointer (*mk_vector)(scheme *sc, int len);
+ pointer (*mk_foreign_func)(scheme *sc, foreign_func f);
+ pointer (*mk_closure)(scheme *sc, pointer c, pointer e);
+ void (*putstr)(scheme *sc, const char *s);
+ void (*putcharacter)(scheme *sc, gunichar c);
+
+ int (*is_string)(pointer p);
+ int (*string_length)(pointer p);
+ char *(*string_value)(pointer p);
+ int (*is_number)(pointer p);
+ num (*nvalue)(pointer p);
+ long (*ivalue)(pointer p);
+ double (*rvalue)(pointer p);
+ int (*is_integer)(pointer p);
+ int (*is_real)(pointer p);
+ int (*is_character)(pointer p);
+ gunichar (*charvalue)(pointer p);
+ int (*is_list)(scheme *sc, pointer p);
+ int (*is_vector)(pointer p);
+ int (*list_length)(scheme *sc, pointer p);
+ long (*vector_length)(pointer vec);
+ void (*fill_vector)(pointer vec, pointer elem);
+ pointer (*vector_elem)(pointer vec, int ielem);
+ pointer (*set_vector_elem)(pointer vec, int ielem, pointer newel);
+
+ int (*is_port)(pointer p);
+
+ int (*is_pair)(pointer p);
+ pointer (*pair_car)(pointer p);
+ pointer (*pair_cdr)(pointer p);
+ pointer (*set_car)(pointer p, pointer q);
+ pointer (*set_cdr)(pointer p, pointer q);
+
+ int (*is_symbol)(pointer p);
+ char *(*symname)(pointer p);
+
+ int (*is_syntax)(pointer p);
+ int (*is_proc)(pointer p);
+ int (*is_foreign)(pointer p);
+ char *(*syntaxname)(pointer p);
+ int (*is_closure)(pointer p);
+ int (*is_macro)(pointer p);
+ pointer (*closure_code)(pointer p);
+ pointer (*closure_env)(pointer p);
+
+ int (*is_continuation)(pointer p);
+ int (*is_promise)(pointer p);
+ int (*is_environment)(pointer p);
+ int (*is_immutable)(pointer p);
+ void (*setimmutable)(pointer p);
+
+ void (*load_file)(scheme *sc, FILE *fin);
+ void (*load_string)(scheme *sc, const char *input);
+};
+#endif
+
+#if !STANDALONE
+typedef struct scheme_registerable
+{
+ foreign_func f;
+ const char * name;
+}
+scheme_registerable;
+
+void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr);
+void scheme_register_foreign_func_list(scheme * sc,
+ scheme_registerable * list,
+ int n);
+
+#endif /* !STANDALONE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*
+Local variables:
+c-file-style: "k&r"
+End:
+*/