summaryrefslogtreecommitdiffstats
path: root/plug-ins/imagemap
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
commit3c57dd931145d43f2b0aef96c4d178135956bf91 (patch)
tree3de698981e9f0cc2c4f9569b19a5f3595e741f6b /plug-ins/imagemap
parentInitial commit. (diff)
downloadgimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz
gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plug-ins/imagemap')
-rw-r--r--plug-ins/imagemap/Makefile.am216
-rw-r--r--plug-ins/imagemap/Makefile.in1531
-rw-r--r--plug-ins/imagemap/images/Makefile.am27
-rw-r--r--plug-ins/imagemap/images/Makefile.in773
-rw-r--r--plug-ins/imagemap/images/stock-circle.pngbin0 -> 355 bytes
-rw-r--r--plug-ins/imagemap/images/stock-coord.pngbin0 -> 147 bytes
-rw-r--r--plug-ins/imagemap/images/stock-dimension.pngbin0 -> 179 bytes
-rw-r--r--plug-ins/imagemap/images/stock-java.pngbin0 -> 1017 bytes
-rw-r--r--plug-ins/imagemap/images/stock-polygon.pngbin0 -> 291 bytes
-rw-r--r--plug-ins/imagemap/images/stock-rectangle.pngbin0 -> 221 bytes
-rw-r--r--plug-ins/imagemap/images/stock-to-back.pngbin0 -> 305 bytes
-rw-r--r--plug-ins/imagemap/images/stock-to-front.pngbin0 -> 261 bytes
-rw-r--r--plug-ins/imagemap/imap_about.c62
-rw-r--r--plug-ins/imagemap/imap_about.h28
-rw-r--r--plug-ins/imagemap/imap_browse.c172
-rw-r--r--plug-ins/imagemap/imap_browse.h46
-rw-r--r--plug-ins/imagemap/imap_cern.l93
-rw-r--r--plug-ins/imagemap/imap_cern.y184
-rw-r--r--plug-ins/imagemap/imap_cern_lex.c1939
-rw-r--r--plug-ins/imagemap/imap_cern_parse.c1822
-rw-r--r--plug-ins/imagemap/imap_cern_parse.h110
-rw-r--r--plug-ins/imagemap/imap_circle.c405
-rw-r--r--plug-ins/imagemap/imap_circle.h40
-rw-r--r--plug-ins/imagemap/imap_cmd_clear.c72
-rw-r--r--plug-ins/imagemap/imap_cmd_copy.c71
-rw-r--r--plug-ins/imagemap/imap_cmd_copy_object.c84
-rw-r--r--plug-ins/imagemap/imap_cmd_create.c82
-rw-r--r--plug-ins/imagemap/imap_cmd_cut.c92
-rw-r--r--plug-ins/imagemap/imap_cmd_cut_object.c62
-rw-r--r--plug-ins/imagemap/imap_cmd_delete.c83
-rw-r--r--plug-ins/imagemap/imap_cmd_delete_point.c86
-rw-r--r--plug-ins/imagemap/imap_cmd_edit_object.c73
-rw-r--r--plug-ins/imagemap/imap_cmd_gimp_guides.c260
-rw-r--r--plug-ins/imagemap/imap_cmd_guides.c279
-rw-r--r--plug-ins/imagemap/imap_cmd_insert_point.c96
-rw-r--r--plug-ins/imagemap/imap_cmd_move.c166
-rw-r--r--plug-ins/imagemap/imap_cmd_move_down.c82
-rw-r--r--plug-ins/imagemap/imap_cmd_move_sash.c150
-rw-r--r--plug-ins/imagemap/imap_cmd_move_selected.c72
-rw-r--r--plug-ins/imagemap/imap_cmd_move_to_front.c83
-rw-r--r--plug-ins/imagemap/imap_cmd_move_up.c81
-rw-r--r--plug-ins/imagemap/imap_cmd_object_down.c78
-rw-r--r--plug-ins/imagemap/imap_cmd_object_move.c80
-rw-r--r--plug-ins/imagemap/imap_cmd_object_up.c78
-rw-r--r--plug-ins/imagemap/imap_cmd_paste.c71
-rw-r--r--plug-ins/imagemap/imap_cmd_select.c75
-rw-r--r--plug-ins/imagemap/imap_cmd_select_all.c74
-rw-r--r--plug-ins/imagemap/imap_cmd_select_next.c76
-rw-r--r--plug-ins/imagemap/imap_cmd_select_prev.c76
-rw-r--r--plug-ins/imagemap/imap_cmd_select_region.c142
-rw-r--r--plug-ins/imagemap/imap_cmd_send_to_back.c83
-rw-r--r--plug-ins/imagemap/imap_cmd_unselect.c76
-rw-r--r--plug-ins/imagemap/imap_cmd_unselect_all.c90
-rw-r--r--plug-ins/imagemap/imap_command.c384
-rw-r--r--plug-ins/imagemap/imap_command.h103
-rw-r--r--plug-ins/imagemap/imap_commands.h64
-rw-r--r--plug-ins/imagemap/imap_csim.l137
-rw-r--r--plug-ins/imagemap/imap_csim.y396
-rw-r--r--plug-ins/imagemap/imap_csim_lex.c2054
-rw-r--r--plug-ins/imagemap/imap_csim_parse.c2131
-rw-r--r--plug-ins/imagemap/imap_csim_parse.h142
-rw-r--r--plug-ins/imagemap/imap_default_dialog.c184
-rw-r--r--plug-ins/imagemap/imap_default_dialog.h59
-rw-r--r--plug-ins/imagemap/imap_edit_area_info.c560
-rw-r--r--plug-ins/imagemap/imap_edit_area_info.h66
-rw-r--r--plug-ins/imagemap/imap_file.c180
-rw-r--r--plug-ins/imagemap/imap_file.h34
-rw-r--r--plug-ins/imagemap/imap_grid.c414
-rw-r--r--plug-ins/imagemap/imap_grid.h34
-rw-r--r--plug-ins/imagemap/imap_main.c1306
-rw-r--r--plug-ins/imagemap/imap_main.h125
-rw-r--r--plug-ins/imagemap/imap_menu.c551
-rw-r--r--plug-ins/imagemap/imap_menu.h65
-rw-r--r--plug-ins/imagemap/imap_menu_funcs.c58
-rw-r--r--plug-ins/imagemap/imap_menu_funcs.h39
-rw-r--r--plug-ins/imagemap/imap_misc.c52
-rw-r--r--plug-ins/imagemap/imap_misc.h31
-rw-r--r--plug-ins/imagemap/imap_mru.c105
-rw-r--r--plug-ins/imagemap/imap_mru.h45
-rw-r--r--plug-ins/imagemap/imap_ncsa.l112
-rw-r--r--plug-ins/imagemap/imap_ncsa.y195
-rw-r--r--plug-ins/imagemap/imap_ncsa_lex.c1917
-rw-r--r--plug-ins/imagemap/imap_ncsa_parse.c1830
-rw-r--r--plug-ins/imagemap/imap_ncsa_parse.h112
-rw-r--r--plug-ins/imagemap/imap_object.c1040
-rw-r--r--plug-ins/imagemap/imap_object.h253
-rw-r--r--plug-ins/imagemap/imap_object_popup.c60
-rw-r--r--plug-ins/imagemap/imap_object_popup.h39
-rw-r--r--plug-ins/imagemap/imap_polygon.c854
-rw-r--r--plug-ins/imagemap/imap_polygon.h45
-rw-r--r--plug-ins/imagemap/imap_preferences.c527
-rw-r--r--plug-ins/imagemap/imap_preferences.h56
-rw-r--r--plug-ins/imagemap/imap_preview.c402
-rw-r--r--plug-ins/imagemap/imap_preview.h55
-rw-r--r--plug-ins/imagemap/imap_rectangle.c538
-rw-r--r--plug-ins/imagemap/imap_rectangle.h41
-rw-r--r--plug-ins/imagemap/imap_selection.c452
-rw-r--r--plug-ins/imagemap/imap_selection.h64
-rw-r--r--plug-ins/imagemap/imap_settings.c188
-rw-r--r--plug-ins/imagemap/imap_settings.h28
-rw-r--r--plug-ins/imagemap/imap_source.c91
-rw-r--r--plug-ins/imagemap/imap_source.h28
-rw-r--r--plug-ins/imagemap/imap_statusbar.c153
-rw-r--r--plug-ins/imagemap/imap_statusbar.h47
-rw-r--r--plug-ins/imagemap/imap_stock.c89
-rw-r--r--plug-ins/imagemap/imap_stock.h39
-rw-r--r--plug-ins/imagemap/imap_string.c37
-rw-r--r--plug-ins/imagemap/imap_string.h28
-rw-r--r--plug-ins/imagemap/imap_table.c81
-rw-r--r--plug-ins/imagemap/imap_table.h39
-rw-r--r--plug-ins/imagemap/imap_taglist.c126
-rw-r--r--plug-ins/imagemap/imap_taglist.h44
112 files changed, 29350 insertions, 0 deletions
diff --git a/plug-ins/imagemap/Makefile.am b/plug-ins/imagemap/Makefile.am
new file mode 100644
index 0000000..f24ddb1
--- /dev/null
+++ b/plug-ins/imagemap/Makefile.am
@@ -0,0 +1,216 @@
+## Process this file with automake to produce Makefile.in
+
+if OS_WIN32
+mwindows = -mwindows
+else
+libm = -lm
+endif
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(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
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+
+if HAVE_WINDRES
+include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
+imagemap_RC = imagemap.rc.o
+endif
+
+AM_LDFLAGS = $(mwindows)
+
+SUBDIRS = images
+
+libexecdir = $(gimpplugindir)/plug-ins/imagemap
+
+libexec_PROGRAMS = imagemap
+
+EXTRA_DIST = \
+ imap_cern.l \
+ imap_csim.l \
+ imap_ncsa.l \
+ imap_cern.y \
+ imap_csim.y \
+ imap_ncsa.y
+
+imagemap_SOURCES = \
+ imap_about.c \
+ imap_about.h \
+ imap_browse.c \
+ imap_browse.h \
+ imap_cern_lex.c \
+ imap_cern_parse.c \
+ imap_cern_parse.h \
+ imap_circle.c \
+ imap_circle.h \
+ imap_cmd_clear.c \
+ imap_cmd_copy.c \
+ imap_cmd_copy_object.c \
+ imap_cmd_create.c \
+ imap_cmd_cut.c \
+ imap_cmd_cut_object.c \
+ imap_cmd_delete.c \
+ imap_cmd_delete_point.c \
+ imap_cmd_edit_object.c \
+ imap_cmd_gimp_guides.c \
+ imap_cmd_guides.c \
+ imap_cmd_insert_point.c \
+ imap_cmd_move.c \
+ imap_cmd_move_down.c \
+ imap_cmd_move_sash.c \
+ imap_cmd_move_selected.c \
+ imap_cmd_move_to_front.c \
+ imap_cmd_move_up.c \
+ imap_cmd_object_down.c \
+ imap_cmd_object_move.c \
+ imap_cmd_object_up.c \
+ imap_cmd_paste.c \
+ imap_cmd_select.c \
+ imap_cmd_select_all.c \
+ imap_cmd_select_next.c \
+ imap_cmd_select_prev.c \
+ imap_cmd_select_region.c \
+ imap_cmd_send_to_back.c \
+ imap_cmd_unselect.c \
+ imap_cmd_unselect_all.c \
+ imap_command.c \
+ imap_command.h \
+ imap_commands.h \
+ imap_csim_lex.c \
+ imap_csim_parse.c \
+ imap_csim_parse.h \
+ imap_default_dialog.c \
+ imap_default_dialog.h \
+ imap_edit_area_info.c \
+ imap_edit_area_info.h \
+ imap_file.c \
+ imap_file.h \
+ imap_grid.c \
+ imap_grid.h \
+ imap_main.c \
+ imap_main.h \
+ imap_menu.c \
+ imap_menu.h \
+ imap_menu_funcs.c \
+ imap_menu_funcs.h \
+ imap_misc.c \
+ imap_misc.h \
+ imap_mru.c \
+ imap_mru.h \
+ imap_ncsa_lex.c \
+ imap_ncsa_parse.c \
+ imap_ncsa_parse.h \
+ imap_object.c \
+ imap_object.h \
+ imap_object_popup.c \
+ imap_object_popup.h \
+ imap_polygon.c \
+ imap_polygon.h \
+ imap_preferences.c \
+ imap_preferences.h \
+ imap_preview.c \
+ imap_preview.h \
+ imap_rectangle.c \
+ imap_rectangle.h \
+ imap_selection.c \
+ imap_selection.h \
+ imap_settings.c \
+ imap_settings.h \
+ imap_source.c \
+ imap_source.h \
+ imap_stock.c \
+ imap_stock.h \
+ imap_statusbar.c \
+ imap_statusbar.h \
+ imap_string.c \
+ imap_string.h \
+ imap_table.c \
+ imap_table.h \
+ imap_taglist.c \
+ imap_taglist.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libm) \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(imagemap)
+
+CLEANFILES = y.tab.c y.tab.h
+
+## The following rules are not necessary for most users. They are
+## only used by the maintainers who modify the symbols and grammar
+## that are used for parsing the map files. These rules are very
+## specific and a test for flex and bison in configure.ac would not be
+## appropriate in most cases, so the Makefile rules are included here.
+## In addition, the default rules provided by automake would not be
+## sufficient because the source and target files have different base
+## names and because of the non-standard prefix used in the output
+## code (cern_, csim_, ncsa_).
+
+## Require flex because the standard lex does not support the -P option.
+LEX=flex
+YACC=bison -y
+
+REBUILD_FILES = \
+ imap_cern_lex.c.rebuild \
+ imap_csim_lex.c.rebuild \
+ imap_ncsa_lex.c.rebuild \
+ imap_cern_parse.c.rebuild \
+ imap_csim_parse.c.rebuild \
+ imap_ncsa_parse.c.rebuild \
+ imap_cern_parse.h.rebuild \
+ imap_csim_parse.h.rebuild \
+ imap_ncsa_parse.h.rebuild
+
+rebuild-parsers: $(REBUILD_FILES)
+ @list='$(REBUILD_FILES)'; for p in $$list; do \
+ newfile="`echo $$p | sed -e 's|.rebuild||'`"; \
+ cp $$p $(srcdir)/$$newfile; \
+ done
+
+imap_cern_lex.c.rebuild: imap_cern.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pcern_ -i -t $< > $@
+imap_csim_lex.c.rebuild: imap_csim.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pcsim_ -i -t $< > $@
+imap_ncsa_lex.c.rebuild: imap_ncsa.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pncsa_ -i -t $< > $@
+
+imap_cern_parse.c.rebuild: imap_cern.y
+ $(YACC) $(YFLAGS) -d -p cern_ $<
+ mv -f y.tab.c $@
+imap_csim_parse.c.rebuild: imap_csim.y
+ $(YACC) $(YFLAGS) -d -p csim_ $<
+ mv -f y.tab.c $@
+imap_ncsa_parse.c.rebuild: imap_ncsa.y
+ $(YACC) $(YFLAGS) -d -p ncsa_ $<
+ mv -f y.tab.c $@
+
+imap_cern_parse.h.rebuild: imap_cern.y
+ $(YACC) $(YFLAGS) -d -p cern_ $<
+ mv -f y.tab.h $@
+imap_csim_parse.h.rebuild: imap_csim.y
+ $(YACC) $(YFLAGS) -d -p csim_ $<
+ mv -f y.tab.h $@
+imap_ncsa_parse.h.rebuild: imap_ncsa.y
+ $(YACC) $(YFLAGS) -d -p ncsa_ $<
+ mv -f y.tab.h $@
diff --git a/plug-ins/imagemap/Makefile.in b/plug-ins/imagemap/Makefile.in
new file mode 100644
index 0000000..efb8942
--- /dev/null
+++ b/plug-ins/imagemap/Makefile.in
@@ -0,0 +1,1531 @@
+# 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 = imagemap$(EXEEXT)
+subdir = plug-ins/imagemap
+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_imagemap_OBJECTS = imap_about.$(OBJEXT) imap_browse.$(OBJEXT) \
+ imap_cern_lex.$(OBJEXT) imap_cern_parse.$(OBJEXT) \
+ imap_circle.$(OBJEXT) imap_cmd_clear.$(OBJEXT) \
+ imap_cmd_copy.$(OBJEXT) imap_cmd_copy_object.$(OBJEXT) \
+ imap_cmd_create.$(OBJEXT) imap_cmd_cut.$(OBJEXT) \
+ imap_cmd_cut_object.$(OBJEXT) imap_cmd_delete.$(OBJEXT) \
+ imap_cmd_delete_point.$(OBJEXT) imap_cmd_edit_object.$(OBJEXT) \
+ imap_cmd_gimp_guides.$(OBJEXT) imap_cmd_guides.$(OBJEXT) \
+ imap_cmd_insert_point.$(OBJEXT) imap_cmd_move.$(OBJEXT) \
+ imap_cmd_move_down.$(OBJEXT) imap_cmd_move_sash.$(OBJEXT) \
+ imap_cmd_move_selected.$(OBJEXT) \
+ imap_cmd_move_to_front.$(OBJEXT) imap_cmd_move_up.$(OBJEXT) \
+ imap_cmd_object_down.$(OBJEXT) imap_cmd_object_move.$(OBJEXT) \
+ imap_cmd_object_up.$(OBJEXT) imap_cmd_paste.$(OBJEXT) \
+ imap_cmd_select.$(OBJEXT) imap_cmd_select_all.$(OBJEXT) \
+ imap_cmd_select_next.$(OBJEXT) imap_cmd_select_prev.$(OBJEXT) \
+ imap_cmd_select_region.$(OBJEXT) \
+ imap_cmd_send_to_back.$(OBJEXT) imap_cmd_unselect.$(OBJEXT) \
+ imap_cmd_unselect_all.$(OBJEXT) imap_command.$(OBJEXT) \
+ imap_csim_lex.$(OBJEXT) imap_csim_parse.$(OBJEXT) \
+ imap_default_dialog.$(OBJEXT) imap_edit_area_info.$(OBJEXT) \
+ imap_file.$(OBJEXT) imap_grid.$(OBJEXT) imap_main.$(OBJEXT) \
+ imap_menu.$(OBJEXT) imap_menu_funcs.$(OBJEXT) \
+ imap_misc.$(OBJEXT) imap_mru.$(OBJEXT) imap_ncsa_lex.$(OBJEXT) \
+ imap_ncsa_parse.$(OBJEXT) imap_object.$(OBJEXT) \
+ imap_object_popup.$(OBJEXT) imap_polygon.$(OBJEXT) \
+ imap_preferences.$(OBJEXT) imap_preview.$(OBJEXT) \
+ imap_rectangle.$(OBJEXT) imap_selection.$(OBJEXT) \
+ imap_settings.$(OBJEXT) imap_source.$(OBJEXT) \
+ imap_stock.$(OBJEXT) imap_statusbar.$(OBJEXT) \
+ imap_string.$(OBJEXT) imap_table.$(OBJEXT) \
+ imap_taglist.$(OBJEXT)
+imagemap_OBJECTS = $(am_imagemap_OBJECTS)
+imagemap_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+imagemap_DEPENDENCIES = $(am__DEPENDENCIES_1) $(libgimpui) \
+ $(libgimpwidgets) $(libgimpconfig) $(libgimp) $(libgimpcolor) \
+ $(libgimpmath) $(libgimpbase) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+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)/imap_about.Po \
+ ./$(DEPDIR)/imap_browse.Po ./$(DEPDIR)/imap_cern_lex.Po \
+ ./$(DEPDIR)/imap_cern_parse.Po ./$(DEPDIR)/imap_circle.Po \
+ ./$(DEPDIR)/imap_cmd_clear.Po ./$(DEPDIR)/imap_cmd_copy.Po \
+ ./$(DEPDIR)/imap_cmd_copy_object.Po \
+ ./$(DEPDIR)/imap_cmd_create.Po ./$(DEPDIR)/imap_cmd_cut.Po \
+ ./$(DEPDIR)/imap_cmd_cut_object.Po \
+ ./$(DEPDIR)/imap_cmd_delete.Po \
+ ./$(DEPDIR)/imap_cmd_delete_point.Po \
+ ./$(DEPDIR)/imap_cmd_edit_object.Po \
+ ./$(DEPDIR)/imap_cmd_gimp_guides.Po \
+ ./$(DEPDIR)/imap_cmd_guides.Po \
+ ./$(DEPDIR)/imap_cmd_insert_point.Po \
+ ./$(DEPDIR)/imap_cmd_move.Po ./$(DEPDIR)/imap_cmd_move_down.Po \
+ ./$(DEPDIR)/imap_cmd_move_sash.Po \
+ ./$(DEPDIR)/imap_cmd_move_selected.Po \
+ ./$(DEPDIR)/imap_cmd_move_to_front.Po \
+ ./$(DEPDIR)/imap_cmd_move_up.Po \
+ ./$(DEPDIR)/imap_cmd_object_down.Po \
+ ./$(DEPDIR)/imap_cmd_object_move.Po \
+ ./$(DEPDIR)/imap_cmd_object_up.Po \
+ ./$(DEPDIR)/imap_cmd_paste.Po ./$(DEPDIR)/imap_cmd_select.Po \
+ ./$(DEPDIR)/imap_cmd_select_all.Po \
+ ./$(DEPDIR)/imap_cmd_select_next.Po \
+ ./$(DEPDIR)/imap_cmd_select_prev.Po \
+ ./$(DEPDIR)/imap_cmd_select_region.Po \
+ ./$(DEPDIR)/imap_cmd_send_to_back.Po \
+ ./$(DEPDIR)/imap_cmd_unselect.Po \
+ ./$(DEPDIR)/imap_cmd_unselect_all.Po \
+ ./$(DEPDIR)/imap_command.Po ./$(DEPDIR)/imap_csim_lex.Po \
+ ./$(DEPDIR)/imap_csim_parse.Po \
+ ./$(DEPDIR)/imap_default_dialog.Po \
+ ./$(DEPDIR)/imap_edit_area_info.Po ./$(DEPDIR)/imap_file.Po \
+ ./$(DEPDIR)/imap_grid.Po ./$(DEPDIR)/imap_main.Po \
+ ./$(DEPDIR)/imap_menu.Po ./$(DEPDIR)/imap_menu_funcs.Po \
+ ./$(DEPDIR)/imap_misc.Po ./$(DEPDIR)/imap_mru.Po \
+ ./$(DEPDIR)/imap_ncsa_lex.Po ./$(DEPDIR)/imap_ncsa_parse.Po \
+ ./$(DEPDIR)/imap_object.Po ./$(DEPDIR)/imap_object_popup.Po \
+ ./$(DEPDIR)/imap_polygon.Po ./$(DEPDIR)/imap_preferences.Po \
+ ./$(DEPDIR)/imap_preview.Po ./$(DEPDIR)/imap_rectangle.Po \
+ ./$(DEPDIR)/imap_selection.Po ./$(DEPDIR)/imap_settings.Po \
+ ./$(DEPDIR)/imap_source.Po ./$(DEPDIR)/imap_statusbar.Po \
+ ./$(DEPDIR)/imap_stock.Po ./$(DEPDIR)/imap_string.Po \
+ ./$(DEPDIR)/imap_table.Po ./$(DEPDIR)/imap_taglist.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 = $(imagemap_SOURCES)
+DIST_SOURCES = $(imagemap_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/imagemap
+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@
+@OS_WIN32_TRUE@mwindows = -mwindows
+@OS_WIN32_FALSE@libm = -lm
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(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
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+@HAVE_WINDRES_TRUE@GIMPPLUGINRC = $(top_builddir)/build/windows/gimp-plug-ins.rc
+@HAVE_WINDRES_TRUE@imagemap_RC = imagemap.rc.o
+AM_LDFLAGS = $(mwindows)
+SUBDIRS = images
+EXTRA_DIST = \
+ imap_cern.l \
+ imap_csim.l \
+ imap_ncsa.l \
+ imap_cern.y \
+ imap_csim.y \
+ imap_ncsa.y
+
+imagemap_SOURCES = \
+ imap_about.c \
+ imap_about.h \
+ imap_browse.c \
+ imap_browse.h \
+ imap_cern_lex.c \
+ imap_cern_parse.c \
+ imap_cern_parse.h \
+ imap_circle.c \
+ imap_circle.h \
+ imap_cmd_clear.c \
+ imap_cmd_copy.c \
+ imap_cmd_copy_object.c \
+ imap_cmd_create.c \
+ imap_cmd_cut.c \
+ imap_cmd_cut_object.c \
+ imap_cmd_delete.c \
+ imap_cmd_delete_point.c \
+ imap_cmd_edit_object.c \
+ imap_cmd_gimp_guides.c \
+ imap_cmd_guides.c \
+ imap_cmd_insert_point.c \
+ imap_cmd_move.c \
+ imap_cmd_move_down.c \
+ imap_cmd_move_sash.c \
+ imap_cmd_move_selected.c \
+ imap_cmd_move_to_front.c \
+ imap_cmd_move_up.c \
+ imap_cmd_object_down.c \
+ imap_cmd_object_move.c \
+ imap_cmd_object_up.c \
+ imap_cmd_paste.c \
+ imap_cmd_select.c \
+ imap_cmd_select_all.c \
+ imap_cmd_select_next.c \
+ imap_cmd_select_prev.c \
+ imap_cmd_select_region.c \
+ imap_cmd_send_to_back.c \
+ imap_cmd_unselect.c \
+ imap_cmd_unselect_all.c \
+ imap_command.c \
+ imap_command.h \
+ imap_commands.h \
+ imap_csim_lex.c \
+ imap_csim_parse.c \
+ imap_csim_parse.h \
+ imap_default_dialog.c \
+ imap_default_dialog.h \
+ imap_edit_area_info.c \
+ imap_edit_area_info.h \
+ imap_file.c \
+ imap_file.h \
+ imap_grid.c \
+ imap_grid.h \
+ imap_main.c \
+ imap_main.h \
+ imap_menu.c \
+ imap_menu.h \
+ imap_menu_funcs.c \
+ imap_menu_funcs.h \
+ imap_misc.c \
+ imap_misc.h \
+ imap_mru.c \
+ imap_mru.h \
+ imap_ncsa_lex.c \
+ imap_ncsa_parse.c \
+ imap_ncsa_parse.h \
+ imap_object.c \
+ imap_object.h \
+ imap_object_popup.c \
+ imap_object_popup.h \
+ imap_polygon.c \
+ imap_polygon.h \
+ imap_preferences.c \
+ imap_preferences.h \
+ imap_preview.c \
+ imap_preview.h \
+ imap_rectangle.c \
+ imap_rectangle.h \
+ imap_selection.c \
+ imap_selection.h \
+ imap_settings.c \
+ imap_settings.h \
+ imap_source.c \
+ imap_source.h \
+ imap_stock.c \
+ imap_stock.h \
+ imap_statusbar.c \
+ imap_statusbar.h \
+ imap_string.c \
+ imap_string.h \
+ imap_table.c \
+ imap_table.h \
+ imap_taglist.c \
+ imap_taglist.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libm) \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(imagemap)
+
+CLEANFILES = y.tab.c y.tab.h
+LEX = flex
+YACC = bison -y
+REBUILD_FILES = \
+ imap_cern_lex.c.rebuild \
+ imap_csim_lex.c.rebuild \
+ imap_ncsa_lex.c.rebuild \
+ imap_cern_parse.c.rebuild \
+ imap_csim_parse.c.rebuild \
+ imap_ncsa_parse.c.rebuild \
+ imap_cern_parse.h.rebuild \
+ imap_csim_parse.h.rebuild \
+ imap_ncsa_parse.h.rebuild
+
+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/imagemap/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/imagemap/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
+
+imagemap$(EXEEXT): $(imagemap_OBJECTS) $(imagemap_DEPENDENCIES) $(EXTRA_imagemap_DEPENDENCIES)
+ @rm -f imagemap$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(imagemap_OBJECTS) $(imagemap_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_about.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_browse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cern_lex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cern_parse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_circle.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_clear.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_copy.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_copy_object.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_create.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_cut.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_cut_object.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_delete.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_delete_point.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_edit_object.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_gimp_guides.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_guides.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_insert_point.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move_down.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move_sash.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move_selected.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move_to_front.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_move_up.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_object_down.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_object_move.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_object_up.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_paste.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_select.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_select_all.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_select_next.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_select_prev.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_select_region.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_send_to_back.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_unselect.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_cmd_unselect_all.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_command.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_csim_lex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_csim_parse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_default_dialog.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_edit_area_info.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_file.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_grid.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_menu.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_menu_funcs.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_misc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_mru.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_ncsa_lex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_ncsa_parse.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_object.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_object_popup.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_polygon.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_preferences.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_preview.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_rectangle.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_selection.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_settings.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_source.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_statusbar.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_stock.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_string.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_table.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap_taglist.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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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)/imap_about.Po
+ -rm -f ./$(DEPDIR)/imap_browse.Po
+ -rm -f ./$(DEPDIR)/imap_cern_lex.Po
+ -rm -f ./$(DEPDIR)/imap_cern_parse.Po
+ -rm -f ./$(DEPDIR)/imap_circle.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_clear.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_copy.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_copy_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_create.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_cut.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_cut_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_delete.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_delete_point.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_edit_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_gimp_guides.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_guides.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_insert_point.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_down.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_sash.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_selected.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_to_front.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_up.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_down.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_move.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_up.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_paste.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_all.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_next.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_prev.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_region.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_send_to_back.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_unselect.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_unselect_all.Po
+ -rm -f ./$(DEPDIR)/imap_command.Po
+ -rm -f ./$(DEPDIR)/imap_csim_lex.Po
+ -rm -f ./$(DEPDIR)/imap_csim_parse.Po
+ -rm -f ./$(DEPDIR)/imap_default_dialog.Po
+ -rm -f ./$(DEPDIR)/imap_edit_area_info.Po
+ -rm -f ./$(DEPDIR)/imap_file.Po
+ -rm -f ./$(DEPDIR)/imap_grid.Po
+ -rm -f ./$(DEPDIR)/imap_main.Po
+ -rm -f ./$(DEPDIR)/imap_menu.Po
+ -rm -f ./$(DEPDIR)/imap_menu_funcs.Po
+ -rm -f ./$(DEPDIR)/imap_misc.Po
+ -rm -f ./$(DEPDIR)/imap_mru.Po
+ -rm -f ./$(DEPDIR)/imap_ncsa_lex.Po
+ -rm -f ./$(DEPDIR)/imap_ncsa_parse.Po
+ -rm -f ./$(DEPDIR)/imap_object.Po
+ -rm -f ./$(DEPDIR)/imap_object_popup.Po
+ -rm -f ./$(DEPDIR)/imap_polygon.Po
+ -rm -f ./$(DEPDIR)/imap_preferences.Po
+ -rm -f ./$(DEPDIR)/imap_preview.Po
+ -rm -f ./$(DEPDIR)/imap_rectangle.Po
+ -rm -f ./$(DEPDIR)/imap_selection.Po
+ -rm -f ./$(DEPDIR)/imap_settings.Po
+ -rm -f ./$(DEPDIR)/imap_source.Po
+ -rm -f ./$(DEPDIR)/imap_statusbar.Po
+ -rm -f ./$(DEPDIR)/imap_stock.Po
+ -rm -f ./$(DEPDIR)/imap_string.Po
+ -rm -f ./$(DEPDIR)/imap_table.Po
+ -rm -f ./$(DEPDIR)/imap_taglist.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)/imap_about.Po
+ -rm -f ./$(DEPDIR)/imap_browse.Po
+ -rm -f ./$(DEPDIR)/imap_cern_lex.Po
+ -rm -f ./$(DEPDIR)/imap_cern_parse.Po
+ -rm -f ./$(DEPDIR)/imap_circle.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_clear.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_copy.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_copy_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_create.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_cut.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_cut_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_delete.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_delete_point.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_edit_object.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_gimp_guides.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_guides.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_insert_point.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_down.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_sash.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_selected.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_to_front.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_move_up.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_down.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_move.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_object_up.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_paste.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_all.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_next.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_prev.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_select_region.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_send_to_back.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_unselect.Po
+ -rm -f ./$(DEPDIR)/imap_cmd_unselect_all.Po
+ -rm -f ./$(DEPDIR)/imap_command.Po
+ -rm -f ./$(DEPDIR)/imap_csim_lex.Po
+ -rm -f ./$(DEPDIR)/imap_csim_parse.Po
+ -rm -f ./$(DEPDIR)/imap_default_dialog.Po
+ -rm -f ./$(DEPDIR)/imap_edit_area_info.Po
+ -rm -f ./$(DEPDIR)/imap_file.Po
+ -rm -f ./$(DEPDIR)/imap_grid.Po
+ -rm -f ./$(DEPDIR)/imap_main.Po
+ -rm -f ./$(DEPDIR)/imap_menu.Po
+ -rm -f ./$(DEPDIR)/imap_menu_funcs.Po
+ -rm -f ./$(DEPDIR)/imap_misc.Po
+ -rm -f ./$(DEPDIR)/imap_mru.Po
+ -rm -f ./$(DEPDIR)/imap_ncsa_lex.Po
+ -rm -f ./$(DEPDIR)/imap_ncsa_parse.Po
+ -rm -f ./$(DEPDIR)/imap_object.Po
+ -rm -f ./$(DEPDIR)/imap_object_popup.Po
+ -rm -f ./$(DEPDIR)/imap_polygon.Po
+ -rm -f ./$(DEPDIR)/imap_preferences.Po
+ -rm -f ./$(DEPDIR)/imap_preview.Po
+ -rm -f ./$(DEPDIR)/imap_rectangle.Po
+ -rm -f ./$(DEPDIR)/imap_selection.Po
+ -rm -f ./$(DEPDIR)/imap_settings.Po
+ -rm -f ./$(DEPDIR)/imap_source.Po
+ -rm -f ./$(DEPDIR)/imap_statusbar.Po
+ -rm -f ./$(DEPDIR)/imap_stock.Po
+ -rm -f ./$(DEPDIR)/imap_string.Po
+ -rm -f ./$(DEPDIR)/imap_table.Po
+ -rm -f ./$(DEPDIR)/imap_taglist.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) $@
+
+rebuild-parsers: $(REBUILD_FILES)
+ @list='$(REBUILD_FILES)'; for p in $$list; do \
+ newfile="`echo $$p | sed -e 's|.rebuild||'`"; \
+ cp $$p $(srcdir)/$$newfile; \
+ done
+
+imap_cern_lex.c.rebuild: imap_cern.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pcern_ -i -t $< > $@
+imap_csim_lex.c.rebuild: imap_csim.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pcsim_ -i -t $< > $@
+imap_ncsa_lex.c.rebuild: imap_ncsa.l
+ @$(RM) $@
+ $(LEX) $(LFLAGS) -Pncsa_ -i -t $< > $@
+
+imap_cern_parse.c.rebuild: imap_cern.y
+ $(YACC) $(YFLAGS) -d -p cern_ $<
+ mv -f y.tab.c $@
+imap_csim_parse.c.rebuild: imap_csim.y
+ $(YACC) $(YFLAGS) -d -p csim_ $<
+ mv -f y.tab.c $@
+imap_ncsa_parse.c.rebuild: imap_ncsa.y
+ $(YACC) $(YFLAGS) -d -p ncsa_ $<
+ mv -f y.tab.c $@
+
+imap_cern_parse.h.rebuild: imap_cern.y
+ $(YACC) $(YFLAGS) -d -p cern_ $<
+ mv -f y.tab.h $@
+imap_csim_parse.h.rebuild: imap_csim.y
+ $(YACC) $(YFLAGS) -d -p csim_ $<
+ mv -f y.tab.h $@
+imap_ncsa_parse.h.rebuild: imap_ncsa.y
+ $(YACC) $(YFLAGS) -d -p ncsa_ $<
+ mv -f y.tab.h $@
+
+# 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/imagemap/images/Makefile.am b/plug-ins/imagemap/images/Makefile.am
new file mode 100644
index 0000000..9cf0b28
--- /dev/null
+++ b/plug-ins/imagemap/images/Makefile.am
@@ -0,0 +1,27 @@
+## Process this file with automake to produce Makefile.in
+
+STOCK_IMAGES = \
+ stock-circle.png \
+ stock-coord.png \
+ stock-dimension.png \
+ stock-java.png \
+ stock-polygon.png \
+ stock-rectangle.png \
+ stock-to-back.png \
+ stock-to-front.png
+
+EXTRA_DIST = $(STOCK_IMAGES)
+
+noinst_DATA = imap-stock-pixbufs.h
+CLEANFILES = $(noinst_DATA) stock-icons.list
+
+stock-icons.list: $(STOCK_IMAGES) Makefile.am
+ ( rm -f $@; \
+ for image in $(STOCK_IMAGES); do \
+ echo $$image | \
+ sed -e 's|.*/||' -e 's|-|_|g' -e 's|\.png$$||' >> $@; \
+ echo " $(srcdir)/$$image" >> $@; \
+ done )
+
+$(srcdir)/imap-stock-pixbufs.h: stock-icons.list
+ $(GDK_PIXBUF_CSOURCE) --raw --build-list `cat stock-icons.list` > $(@F)
diff --git a/plug-ins/imagemap/images/Makefile.in b/plug-ins/imagemap/images/Makefile.in
new file mode 100644
index 0000000..48c8353
--- /dev/null
+++ b/plug-ins/imagemap/images/Makefile.in
@@ -0,0 +1,773 @@
+# 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/imagemap/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
+DATA = $(noinst_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@
+STOCK_IMAGES = \
+ stock-circle.png \
+ stock-coord.png \
+ stock-dimension.png \
+ stock-java.png \
+ stock-polygon.png \
+ stock-rectangle.png \
+ stock-to-back.png \
+ stock-to-front.png
+
+EXTRA_DIST = $(STOCK_IMAGES)
+noinst_DATA = imap-stock-pixbufs.h
+CLEANFILES = $(noinst_DATA) stock-icons.list
+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/imagemap/images/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/imagemap/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
+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:
+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:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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-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:
+
+.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-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
+
+.PRECIOUS: Makefile
+
+
+stock-icons.list: $(STOCK_IMAGES) Makefile.am
+ ( rm -f $@; \
+ for image in $(STOCK_IMAGES); do \
+ echo $$image | \
+ sed -e 's|.*/||' -e 's|-|_|g' -e 's|\.png$$||' >> $@; \
+ echo " $(srcdir)/$$image" >> $@; \
+ done )
+
+$(srcdir)/imap-stock-pixbufs.h: stock-icons.list
+ $(GDK_PIXBUF_CSOURCE) --raw --build-list `cat stock-icons.list` > $(@F)
+
+# 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/imagemap/images/stock-circle.png b/plug-ins/imagemap/images/stock-circle.png
new file mode 100644
index 0000000..e81b2ea
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-circle.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-coord.png b/plug-ins/imagemap/images/stock-coord.png
new file mode 100644
index 0000000..6276054
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-coord.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-dimension.png b/plug-ins/imagemap/images/stock-dimension.png
new file mode 100644
index 0000000..d556717
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-dimension.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-java.png b/plug-ins/imagemap/images/stock-java.png
new file mode 100644
index 0000000..5c1a8d9
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-java.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-polygon.png b/plug-ins/imagemap/images/stock-polygon.png
new file mode 100644
index 0000000..4ec7754
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-polygon.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-rectangle.png b/plug-ins/imagemap/images/stock-rectangle.png
new file mode 100644
index 0000000..901c3e2
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-rectangle.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-to-back.png b/plug-ins/imagemap/images/stock-to-back.png
new file mode 100644
index 0000000..6438104
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-to-back.png
Binary files differ
diff --git a/plug-ins/imagemap/images/stock-to-front.png b/plug-ins/imagemap/images/stock-to-front.png
new file mode 100644
index 0000000..ef0880d
--- /dev/null
+++ b/plug-ins/imagemap/images/stock-to-front.png
Binary files differ
diff --git a/plug-ins/imagemap/imap_about.c b/plug-ins/imagemap/imap_about.c
new file mode 100644
index 0000000..81b4414
--- /dev/null
+++ b/plug-ins/imagemap/imap_about.c
@@ -0,0 +1,62 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_about.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+void
+do_about_dialog(void)
+{
+ static GtkWidget *dialog;
+ if (!dialog)
+ {
+ const gchar* authors[] = {"Maurits Rijk (m.rijk@chello.nl)", NULL};
+
+ dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+ "transient-for", get_dialog(),
+ "program-name", _("Image Map Plug-in"),
+ "version", "2.3",
+ "authors", authors,
+ "copyright",
+ _("Copyright © 1999-2005 by Maurits Rijk"),
+ "license",
+ _("Released under the GNU General Public License"),
+ NULL);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy),
+ dialog);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &dialog);
+
+ }
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
diff --git a/plug-ins/imagemap/imap_about.h b/plug-ins/imagemap/imap_about.h
new file mode 100644
index 0000000..4834a75
--- /dev/null
+++ b/plug-ins/imagemap/imap_about.h
@@ -0,0 +1,28 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_ABOUT_H
+#define _IMAP_ABOUT_H
+
+void do_about_dialog(void);
+
+#endif /* _IMAP_ABOUT_H */
diff --git a/plug-ins/imagemap/imap_browse.c b/plug-ins/imagemap/imap_browse.c
new file mode 100644
index 0000000..11a8522
--- /dev/null
+++ b/plug-ins/imagemap/imap_browse.c
@@ -0,0 +1,172 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 "libgimp/gimpui.h"
+
+#include "imap_browse.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static const GtkTargetEntry target_table[] =
+{
+ {"STRING", 0, 1 },
+ {"text/plain", 0, 2 }
+};
+
+
+static void
+select_cb (GtkWidget *dialog,
+ gint response_id,
+ BrowseWidget_t *browse)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ gchar *p;
+ gchar *file;
+
+ file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ p = (browse->filter ?
+ browse->filter (file, browse->filter_data) : file);
+
+ gtk_entry_set_text (GTK_ENTRY (browse->file), p);
+
+ if (browse->filter)
+ g_free (p);
+
+ g_free (file);
+ }
+
+ gtk_widget_hide (dialog);
+ gtk_widget_grab_focus (browse->file);
+}
+
+static void
+browse_cb (GtkWidget *widget,
+ BrowseWidget_t *browse)
+{
+ if (!browse->file_chooser)
+ {
+ GtkWidget *dialog;
+
+ dialog = browse->file_chooser =
+ gtk_file_chooser_dialog_new (browse->name,
+ GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &dialog);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (select_cb),
+ browse);
+ }
+
+ gtk_window_present (GTK_WINDOW (browse->file_chooser));
+}
+
+static void
+handle_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *data, guint info, guint time)
+{
+ gboolean success = FALSE;
+
+ if (gtk_selection_data_get_length (data) >= 0 &&
+ gtk_selection_data_get_format (data) == 8)
+ {
+ const gchar *text = (const gchar *) gtk_selection_data_get_data (data);
+
+ if (g_utf8_validate (text, -1, NULL))
+ {
+ gtk_entry_set_text (GTK_ENTRY (widget), text);
+ success = TRUE;
+ }
+ }
+
+ gtk_drag_finish(context, success, FALSE, time);
+}
+
+BrowseWidget_t*
+browse_widget_new (const gchar *name)
+{
+ BrowseWidget_t *browse = g_new(BrowseWidget_t, 1);
+ GtkWidget *button;
+ GtkWidget *icon;
+
+ browse->file_chooser = NULL;
+ browse->name = name;
+ browse->filter = NULL;
+
+ browse->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_widget_show (browse->hbox);
+
+ browse->file = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX(browse->hbox), browse->file, TRUE, TRUE, 0);
+ gtk_drag_dest_set (browse->file, GTK_DEST_DEFAULT_ALL, target_table,
+ 2, GDK_ACTION_COPY);
+ g_signal_connect (browse->file, "drag-data-received",
+ G_CALLBACK(handle_drop), NULL);
+
+ gtk_widget_show (browse->file);
+
+ browse->button = button = gtk_button_new ();
+ icon = gtk_image_new_from_icon_name (GIMP_ICON_DOCUMENT_OPEN,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_container_add (GTK_CONTAINER (button), icon);
+ gtk_widget_show (icon);
+
+ gtk_box_pack_end(GTK_BOX (browse->hbox), button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK(browse_cb), (gpointer) browse);
+ gtk_widget_show (button);
+
+ return browse;
+}
+
+void
+browse_widget_set_filename(BrowseWidget_t *browse, const gchar *filename)
+{
+ gtk_entry_set_text (GTK_ENTRY (browse->file), filename);
+}
+
+void
+browse_widget_set_filter(BrowseWidget_t *browse, BrowseFilter_t filter,
+ gpointer data)
+{
+ browse->filter = filter;
+ browse->filter_data = data;
+}
diff --git a/plug-ins/imagemap/imap_browse.h b/plug-ins/imagemap/imap_browse.h
new file mode 100644
index 0000000..e86c1c8
--- /dev/null
+++ b/plug-ins/imagemap/imap_browse.h
@@ -0,0 +1,46 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_BROWSE_H
+#define _IMAP_BROWSE_H
+
+typedef gchar* (*BrowseFilter_t) (const gchar *, gpointer data);
+
+typedef struct
+{
+ const gchar *name;
+ BrowseFilter_t filter;
+ gpointer filter_data;
+ GtkWidget *hbox;
+ GtkWidget *file;
+ GtkWidget *button;
+ GtkWidget *file_chooser;
+} BrowseWidget_t;
+
+BrowseWidget_t * browse_widget_new (const gchar *name);
+void browse_widget_set_filename (BrowseWidget_t *browse,
+ const gchar *filename);
+void browse_widget_set_filter (BrowseWidget_t *browse,
+ BrowseFilter_t filter,
+ gpointer data);
+
+#endif /* _IMAP_BROWSE_H */
diff --git a/plug-ins/imagemap/imap_cern.l b/plug-ins/imagemap/imap_cern.l
new file mode 100644
index 0000000..95e7ad0
--- /dev/null
+++ b/plug-ins/imagemap/imap_cern.l
@@ -0,0 +1,93 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_cern_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+%}
+
+%option noyywrap
+%option noinput
+%option nounput
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_\-]*
+WS [ \t\n]+
+
+%x comment
+
+%%
+
+RECT{WS}\(4096,4096\){WS}\(4096,4096\).*#\$AUTHOR: {
+ BEGIN(comment);
+ return AUTHOR;
+ }
+
+RECT{WS}\(4096,4096\){WS}\(4096,4096\).*#\$DESCRIPTION: {
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+
+RECT{WS}\(4096,4096\){WS}\(4096,4096\) {
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+
+<comment>.*$ {
+ BEGIN(INITIAL);
+ cern_lval.id = g_strndup (yytext, yyleng);
+ return COMMENT;
+ }
+
+RECT return RECTANGLE;
+
+CIRC return CIRCLE;
+
+POLY return POLYGON;
+
+DEFAULT return DEFAULT;
+
+[^ ,\t\n]+$ {
+ cern_lval.id = g_strndup (yytext, yyleng);
+ return LINK;
+ }
+
+-?{DIGIT}*"."?{DIGIT}*([Ee][-+]?{DIGIT}*)? {
+ cern_lval.value = g_ascii_strtod (yytext, NULL);
+ return FLOAT;
+ }
+
+{WS} ; /* Eat white space */
+
+. return *yytext;
+
+%%
+
+
diff --git a/plug-ins/imagemap/imap_cern.y b/plug-ins/imagemap/imap_cern.y
new file mode 100644
index 0000000..251eb16
--- /dev/null
+++ b/plug-ins/imagemap/imap_cern.y
@@ -0,0 +1,184 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <math.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int cern_lex(void);
+extern int cern_restart(FILE *cern_in);
+static void cern_error(char* s);
+
+static Object_t *current_object;
+
+%}
+
+%union {
+ int val;
+ double value;
+ char *id;
+}
+
+%token<val> RECTANGLE POLYGON CIRCLE DEFAULT
+%token<val> AUTHOR DESCRIPTION BEGIN_COMMENT
+%token<value> FLOAT
+%token<id> COMMENT LINK
+
+%%
+
+cern_file : area_list
+ ;
+
+area_list : /* Empty */
+ | area_list area
+ ;
+
+area : default
+ | rectangle
+ | circle
+ | polygon
+ | comment_line
+ ;
+
+default : DEFAULT LINK
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->default_url, $2);
+ g_free ($2);
+ }
+ ;
+
+
+rectangle : RECTANGLE '(' FLOAT ',' FLOAT ')' '(' FLOAT ',' FLOAT ')' LINK
+ {
+ gint x = (gint) $3;
+ gint y = (gint) $5;
+ gint width = (gint) fabs($8 - x);
+ gint height = (gint) fabs($10 - y);
+ current_object = create_rectangle(x, y, width, height);
+ object_set_url(current_object, $12);
+ add_shape(current_object);
+ g_free ($12);
+ }
+ ;
+
+circle : CIRCLE '(' FLOAT ',' FLOAT ')' FLOAT LINK
+ {
+ gint x = (gint) $3;
+ gint y = (gint) $5;
+ gint r = (gint) $7;
+ current_object = create_circle(x, y, r);
+ object_set_url(current_object, $8);
+ add_shape(current_object);
+ g_free ($8);
+ }
+ ;
+
+polygon : POLYGON {current_object = create_polygon(NULL);} coord_list LINK
+ {
+ object_set_url(current_object, $4);
+ add_shape(current_object);
+ g_free ($4);
+ }
+ ;
+
+coord_list : /* Empty */
+ | coord_list coord
+ {
+ }
+ ;
+
+coord : '(' FLOAT ',' FLOAT ')'
+ {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GdkPoint *point = new_point((gint) $2, (gint) $4);
+ polygon->points = g_list_append(polygon->points,
+ (gpointer) point);
+ }
+ ;
+
+comment_line : author_line
+ | description_line
+ | real_comment
+ ;
+
+real_comment : BEGIN_COMMENT COMMENT
+ {
+ g_free ($2);
+ }
+ ;
+
+author_line : AUTHOR COMMENT
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->author, $2);
+ g_free ($2);
+ }
+ ;
+
+description_line: DESCRIPTION COMMENT
+ {
+ MapInfo_t *info = get_map_info();
+ gchar *description;
+
+ description = g_strconcat(info->description, $2, "\n",
+ NULL);
+ g_strreplace(&info->description, description);
+ g_free ($2);
+ }
+ ;
+
+
+%%
+
+static void
+cern_error(char* s)
+{
+ extern FILE *cern_in;
+ cern_restart(cern_in);
+}
+
+gboolean
+load_cern(const char* filename)
+{
+ gboolean status;
+ extern FILE *cern_in;
+ cern_in = g_fopen(filename, "r");
+ if (cern_in) {
+ status = !cern_parse();
+ fclose(cern_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
diff --git a/plug-ins/imagemap/imap_cern_lex.c b/plug-ins/imagemap/imap_cern_lex.c
new file mode 100644
index 0000000..eb761d2
--- /dev/null
+++ b/plug-ins/imagemap/imap_cern_lex.c
@@ -0,0 +1,1939 @@
+
+#line 3 "<stdout>"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer cern__create_buffer
+#define yy_delete_buffer cern__delete_buffer
+#define yy_flex_debug cern__flex_debug
+#define yy_init_buffer cern__init_buffer
+#define yy_flush_buffer cern__flush_buffer
+#define yy_load_buffer_state cern__load_buffer_state
+#define yy_switch_to_buffer cern__switch_to_buffer
+#define yyin cern_in
+#define yyleng cern_leng
+#define yylex cern_lex
+#define yylineno cern_lineno
+#define yyout cern_out
+#define yyrestart cern_restart
+#define yytext cern_text
+#define yywrap cern_wrap
+#define yyalloc cern_alloc
+#define yyrealloc cern_realloc
+#define yyfree cern_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 36
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE cern_restart(cern_in )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t cern_leng;
+
+extern FILE *cern_in, *cern_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up cern_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up cern_text again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via cern_restart()), so that the user can continue scanning by
+ * just pointing cern_in at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when cern_text is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t cern_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow cern_wrap()'s to do buffer switches
+ * instead of setting up a fresh cern_in. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void cern_restart (FILE *input_file );
+void cern__switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE cern__create_buffer (FILE *file,int size );
+void cern__delete_buffer (YY_BUFFER_STATE b );
+void cern__flush_buffer (YY_BUFFER_STATE b );
+void cern_push_buffer_state (YY_BUFFER_STATE new_buffer );
+void cern_pop_buffer_state (void );
+
+static void cern_ensure_buffer_stack (void );
+static void cern__load_buffer_state (void );
+static void cern__init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER cern__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE cern__scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE cern__scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE cern__scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *cern_alloc (yy_size_t );
+void *cern_realloc (void *,yy_size_t );
+void cern_free (void * );
+
+#define yy_new_buffer cern__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ cern_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cern__create_buffer(cern_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ cern_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ cern__create_buffer(cern_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define cern_wrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *cern_in = (FILE *) 0, *cern_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int cern_lineno;
+
+int cern_lineno = 1;
+
+extern char *cern_text;
+#define yytext_ptr cern_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up cern_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ cern_leng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 13
+#define YY_END_OF_BUFFER 14
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[94] =
+ { 0,
+ 10, 10, 0, 0, 14, 12, 11, 11, 12, 10,
+ 10, 10, 12, 12, 10, 12, 12, 13, 4, 0,
+ 9, 11, 10, 10, 10, 10, 0, 0, 10, 10,
+ 0, 0, 0, 4, 0, 0, 0, 0, 6, 0,
+ 7, 5, 0, 0, 9, 0, 0, 8, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 2, 0
+
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 4, 5, 1, 1, 1, 6,
+ 7, 1, 8, 9, 10, 11, 1, 12, 13, 13,
+ 13, 14, 13, 15, 13, 13, 16, 17, 1, 1,
+ 1, 1, 1, 1, 18, 1, 19, 20, 21, 22,
+ 1, 23, 24, 1, 1, 25, 1, 26, 27, 28,
+ 1, 29, 30, 31, 32, 1, 1, 1, 33, 1,
+ 1, 1, 1, 1, 1, 1, 34, 1, 35, 36,
+
+ 37, 38, 1, 39, 40, 1, 1, 41, 1, 42,
+ 43, 44, 1, 45, 46, 47, 48, 1, 1, 1,
+ 49, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[50] =
+ { 0,
+ 1, 2, 3, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[98] =
+ { 0,
+ 0, 0, 276, 275, 277, 270, 48, 50, 309, 51,
+ 86, 121, 52, 53, 156, 54, 56, 269, 309, 268,
+ 309, 58, 170, 205, 240, 254, 65, 81, 101, 115,
+ 55, 76, 262, 309, 103, 122, 72, 143, 261, 109,
+ 260, 67, 136, 80, 141, 145, 248, 258, 235, 230,
+ 230, 235, 224, 224, 218, 217, 223, 106, 147, 213,
+ 199, 189, 187, 184, 161, 151, 139, 111, 113, 83,
+ 81, 147, 161, 156, 141, 163, 150, 183, 194, 185,
+ 195, 196, 199, 74, 205, 69, 227, 211, 233, 255,
+ 197, 67, 309, 297, 300, 303, 306
+
+ } ;
+
+static yyconst flex_int16_t yy_def[98] =
+ { 0,
+ 93, 1, 94, 94, 93, 95, 93, 93, 93, 95,
+ 95, 95, 95, 95, 95, 95, 95, 96, 93, 95,
+ 93, 93, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 96, 93, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 93, 93, 95, 93, 95, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
+ 97, 97, 0, 93, 93, 93, 93
+
+ } ;
+
+static yyconst flex_int16_t yy_nxt[359] =
+ { 0,
+ 6, 7, 8, 6, 6, 6, 6, 6, 9, 10,
+ 11, 12, 12, 12, 12, 12, 6, 6, 13, 14,
+ 15, 6, 6, 6, 6, 6, 6, 16, 17, 6,
+ 6, 6, 6, 6, 13, 14, 15, 6, 6, 6,
+ 6, 6, 6, 16, 17, 6, 6, 6, 6, 22,
+ 22, 22, 22, 21, 21, 21, 21, 21, 21, 22,
+ 22, 23, 24, 24, 24, 24, 24, 21, 44, 45,
+ 72, 25, 72, 28, 21, 27, 32, 72, 21, 37,
+ 31, 44, 44, 21, 72, 47, 72, 25, 21, 28,
+ 86, 27, 32, 35, 38, 37, 31, 26, 26, 26,
+
+ 26, 26, 36, 21, 41, 21, 25, 59, 59, 35,
+ 38, 21, 30, 30, 30, 30, 30, 21, 36, 70,
+ 41, 39, 25, 21, 21, 69, 30, 30, 30, 30,
+ 30, 23, 24, 24, 24, 24, 24, 39, 21, 40,
+ 43, 25, 44, 44, 72, 21, 47, 21, 59, 59,
+ 72, 73, 60, 72, 68, 40, 43, 25, 21, 72,
+ 46, 77, 67, 29, 72, 29, 72, 30, 30, 30,
+ 30, 30, 21, 42, 66, 48, 46, 77, 74, 79,
+ 75, 26, 26, 26, 26, 26, 72, 76, 72, 42,
+ 25, 48, 65, 78, 74, 79, 75, 72, 72, 72,
+
+ 72, 64, 72, 76, 63, 80, 25, 21, 72, 78,
+ 62, 82, 81, 92, 72, 23, 24, 24, 24, 24,
+ 24, 80, 85, 83, 84, 25, 61, 82, 81, 58,
+ 72, 57, 87, 56, 89, 55, 72, 54, 85, 83,
+ 84, 25, 21, 53, 52, 51, 50, 29, 87, 29,
+ 89, 30, 30, 30, 30, 30, 21, 88, 72, 90,
+ 21, 49, 21, 21, 34, 26, 26, 26, 26, 26,
+ 21, 34, 21, 88, 25, 90, 93, 19, 19, 93,
+ 91, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 25, 93, 93, 93, 93, 93, 91, 18, 18, 18,
+
+ 20, 93, 20, 33, 33, 33, 71, 71, 5, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93
+ } ;
+
+static yyconst flex_int16_t yy_chk[359] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 7,
+ 7, 8, 8, 10, 13, 14, 16, 31, 17, 22,
+ 22, 10, 10, 10, 10, 10, 10, 27, 42, 42,
+ 92, 10, 86, 14, 37, 13, 17, 84, 32, 31,
+ 16, 44, 44, 28, 71, 44, 70, 10, 11, 14,
+ 84, 13, 17, 27, 32, 31, 16, 11, 11, 11,
+
+ 11, 11, 28, 29, 37, 35, 11, 58, 58, 27,
+ 32, 40, 29, 29, 29, 29, 29, 30, 28, 69,
+ 37, 35, 11, 12, 36, 68, 30, 30, 30, 30,
+ 30, 12, 12, 12, 12, 12, 12, 35, 43, 36,
+ 40, 12, 45, 45, 75, 38, 45, 46, 59, 59,
+ 72, 72, 59, 77, 67, 36, 40, 12, 15, 74,
+ 43, 75, 66, 15, 73, 15, 76, 15, 15, 15,
+ 15, 15, 23, 38, 65, 46, 43, 75, 73, 77,
+ 73, 23, 23, 23, 23, 23, 78, 74, 80, 38,
+ 23, 46, 64, 76, 73, 77, 73, 79, 81, 82,
+
+ 91, 63, 83, 74, 62, 78, 23, 24, 85, 76,
+ 61, 80, 79, 91, 88, 24, 24, 24, 24, 24,
+ 24, 78, 83, 81, 82, 24, 60, 80, 79, 57,
+ 87, 56, 85, 55, 88, 54, 89, 53, 83, 81,
+ 82, 24, 25, 52, 51, 50, 49, 25, 85, 25,
+ 88, 25, 25, 25, 25, 25, 26, 87, 90, 89,
+ 48, 47, 41, 39, 33, 26, 26, 26, 26, 26,
+ 20, 18, 6, 87, 26, 89, 5, 4, 3, 0,
+ 90, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 26, 0, 0, 0, 0, 0, 90, 94, 94, 94,
+
+ 95, 0, 95, 96, 96, 96, 97, 97, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int cern__flex_debug;
+int cern__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *cern_text;
+#line 1 "imap_cern.l"
+#line 2 "imap_cern.l"
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_cern_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+#define YY_NO_INPUT 1
+
+#line 617 "<stdout>"
+
+#define INITIAL 0
+#define comment 1
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int cern_lex_destroy (void );
+
+int cern_get_debug (void );
+
+void cern_set_debug (int debug_flag );
+
+YY_EXTRA_TYPE cern_get_extra (void );
+
+void cern_set_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *cern_get_in (void );
+
+void cern_set_in (FILE * in_str );
+
+FILE *cern_get_out (void );
+
+void cern_set_out (FILE * out_str );
+
+yy_size_t cern_get_leng (void );
+
+char *cern_get_text (void );
+
+int cern_get_lineno (void );
+
+void cern_set_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int cern_wrap (void );
+#else
+extern int cern_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( cern_text, cern_leng, 1, cern_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( cern_in )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( cern_in ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, cern_in))==0 && ferror(cern_in)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(cern_in); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int cern_lex (void);
+
+#define YY_DECL int cern_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after cern_text and cern_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 46 "imap_cern.l"
+
+
+#line 801 "<stdout>"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! cern_in )
+ cern_in = stdin;
+
+ if ( ! cern_out )
+ cern_out = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ cern_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ cern__create_buffer(cern_in,YY_BUF_SIZE );
+ }
+
+ cern__load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of cern_text. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 94 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 309 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+/* rule 1 can match eol */
+YY_RULE_SETUP
+#line 48 "imap_cern.l"
+{
+ BEGIN(comment);
+ return AUTHOR;
+ }
+ YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 53 "imap_cern.l"
+{
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+ YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 58 "imap_cern.l"
+{
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+ YY_BREAK
+case 4:
+*yy_cp = (yy_hold_char); /* undo effects of setting up cern_text */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up cern_text again */
+YY_RULE_SETUP
+#line 63 "imap_cern.l"
+{
+ BEGIN(INITIAL);
+ cern_lval.id = g_strndup (cern_text, cern_leng);
+ return COMMENT;
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 69 "imap_cern.l"
+return RECTANGLE;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 71 "imap_cern.l"
+return CIRCLE;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 73 "imap_cern.l"
+return POLYGON;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 75 "imap_cern.l"
+return DEFAULT;
+ YY_BREAK
+case 9:
+*yy_cp = (yy_hold_char); /* undo effects of setting up cern_text */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up cern_text again */
+YY_RULE_SETUP
+#line 77 "imap_cern.l"
+{
+ cern_lval.id = g_strndup (cern_text, cern_leng);
+ return LINK;
+ }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 82 "imap_cern.l"
+{
+ cern_lval.value = g_ascii_strtod (cern_text, NULL);
+ return FLOAT;
+ }
+ YY_BREAK
+case 11:
+/* rule 11 can match eol */
+YY_RULE_SETUP
+#line 87 "imap_cern.l"
+; /* Eat white space */
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 89 "imap_cern.l"
+return *cern_text;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 91 "imap_cern.l"
+ECHO;
+ YY_BREAK
+#line 978 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(comment):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed cern_in at a new source and called
+ * cern_lex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = cern_in;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( cern_wrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * cern_text, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of cern_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ cern_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ cern_restart(cern_in );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) cern_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 94 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 94 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 93);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ cern_restart(cern_in );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( cern_wrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve cern_text */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void cern_restart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ cern_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ cern__create_buffer(cern_in,YY_BUF_SIZE );
+ }
+
+ cern__init_buffer(YY_CURRENT_BUFFER,input_file );
+ cern__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void cern__switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * cern_pop_buffer_state();
+ * cern_push_buffer_state(new_buffer);
+ */
+ cern_ensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ cern__load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (cern_wrap()) processing, but the only time this flag
+ * is looked at is after cern_wrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void cern__load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ cern_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE cern__create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) cern_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cern__create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) cern_alloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cern__create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ cern__init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with cern__create_buffer()
+ *
+ */
+ void cern__delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ cern_free((void *) b->yy_ch_buf );
+
+ cern_free((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a cern_restart() or at EOF.
+ */
+ static void cern__init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ cern__flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then cern__init_buffer was _probably_
+ * called from cern_restart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void cern__flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ cern__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void cern_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ cern_ensure_buffer_stack();
+
+ /* This block is copied from cern__switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from cern__switch_to_buffer. */
+ cern__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void cern_pop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ cern__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ cern__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void cern_ensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)cern_alloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in cern_ensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)cern_realloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in cern_ensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cern__scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) cern_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in cern__scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ cern__switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to cern_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * cern__scan_bytes() instead.
+ */
+YY_BUFFER_STATE cern__scan_string (yyconst char * yystr )
+{
+
+ return cern__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to cern_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE cern__scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) cern_alloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in cern__scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = cern__scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in cern__scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up cern_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ cern_text[cern_leng] = (yy_hold_char); \
+ (yy_c_buf_p) = cern_text + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ cern_leng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int cern_get_lineno (void)
+{
+
+ return cern_lineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *cern_get_in (void)
+{
+ return cern_in;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *cern_get_out (void)
+{
+ return cern_out;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t cern_get_leng (void)
+{
+ return cern_leng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *cern_get_text (void)
+{
+ return cern_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void cern_set_lineno (int line_number )
+{
+
+ cern_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see cern__switch_to_buffer
+ */
+void cern_set_in (FILE * in_str )
+{
+ cern_in = in_str ;
+}
+
+void cern_set_out (FILE * out_str )
+{
+ cern_out = out_str ;
+}
+
+int cern_get_debug (void)
+{
+ return cern__flex_debug;
+}
+
+void cern_set_debug (int bdebug )
+{
+ cern__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from cern_lex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ cern_in = stdin;
+ cern_out = stdout;
+#else
+ cern_in = (FILE *) 0;
+ cern_out = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * cern_lex_init()
+ */
+ return 0;
+}
+
+/* cern_lex_destroy is for both reentrant and non-reentrant scanners. */
+int cern_lex_destroy (void)
+{
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ cern__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ cern_pop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ cern_free((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * cern_lex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *cern_alloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *cern_realloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void cern_free (void * ptr )
+{
+ free( (char *) ptr ); /* see cern_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 91 "imap_cern.l"
+
+
+
+
+
diff --git a/plug-ins/imagemap/imap_cern_parse.c b/plug-ins/imagemap/imap_cern_parse.c
new file mode 100644
index 0000000..56714a2
--- /dev/null
+++ b/plug-ins/imagemap/imap_cern_parse.c
@@ -0,0 +1,1822 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.6.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse cern_parse
+#define yylex cern_lex
+#define yyerror cern_error
+#define yylval cern_lval
+#define yychar cern_char
+#define yydebug cern_debug
+#define yynerrs cern_nerrs
+
+/* Copy the first part of user declarations. */
+/* Line 336 of yacc.c */
+#line 1 "imap_cern.y"
+
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <math.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int cern_lex(void);
+extern int cern_restart(FILE *cern_in);
+static void cern_error(char* s);
+
+static Object_t *current_object;
+
+
+/* Line 336 of yacc.c */
+#line 120 "y.tab.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef CERN_Y_TAB_H
+# define CERN_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cern_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ RECTANGLE = 258,
+ POLYGON = 259,
+ CIRCLE = 260,
+ DEFAULT = 261,
+ AUTHOR = 262,
+ DESCRIPTION = 263,
+ BEGIN_COMMENT = 264,
+ FLOAT = 265,
+ COMMENT = 266,
+ LINK = 267
+ };
+#endif
+/* Tokens. */
+#define RECTANGLE 258
+#define POLYGON 259
+#define CIRCLE 260
+#define DEFAULT 261
+#define AUTHOR 262
+#define DESCRIPTION 263
+#define BEGIN_COMMENT 264
+#define FLOAT 265
+#define COMMENT 266
+#define LINK 267
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 350 of yacc.c */
+#line 46 "imap_cern.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 350 of yacc.c */
+#line 194 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE cern_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int cern_parse (void *YYPARSE_PARAM);
+#else
+int cern_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int cern_parse (void);
+#else
+int cern_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !CERN_Y_TAB_H */
+
+/* Copy the second part of user declarations. */
+
+/* Line 353 of yacc.c */
+#line 222 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 3
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 39
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 16
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 15
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 23
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 51
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 267
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 13, 15, 2, 2, 14, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 5, 6, 9, 11, 13, 15, 17,
+ 19, 22, 35, 44, 45, 50, 51, 54, 60, 62,
+ 64, 66, 69, 72
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 17, 0, -1, 18, -1, -1, 18, 19, -1, 20,
+ -1, 21, -1, 22, -1, 23, -1, 27, -1, 6,
+ 12, -1, 3, 13, 10, 14, 10, 15, 13, 10,
+ 14, 10, 15, 12, -1, 5, 13, 10, 14, 10,
+ 15, 10, 12, -1, -1, 4, 24, 25, 12, -1,
+ -1, 25, 26, -1, 13, 10, 14, 10, 15, -1,
+ 29, -1, 30, -1, 28, -1, 9, 11, -1, 7,
+ 11, -1, 8, 11, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 59, 59, 62, 63, 66, 67, 68, 69, 70,
+ 73, 82, 95, 107, 107, 115, 116, 121, 130, 131,
+ 132, 135, 141, 149
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "RECTANGLE", "POLYGON", "CIRCLE",
+ "DEFAULT", "AUTHOR", "DESCRIPTION", "BEGIN_COMMENT", "FLOAT", "COMMENT",
+ "LINK", "'('", "','", "')'", "$accept", "cern_file", "area_list", "area",
+ "default", "rectangle", "circle", "polygon", "$@1", "coord_list",
+ "coord", "comment_line", "real_comment", "author_line",
+ "description_line", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 40, 44, 41
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 16, 17, 18, 18, 19, 19, 19, 19, 19,
+ 20, 21, 22, 24, 23, 25, 25, 26, 27, 27,
+ 27, 28, 29, 30
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 0, 2, 1, 1, 1, 1, 1,
+ 2, 12, 8, 0, 4, 0, 2, 5, 1, 1,
+ 1, 2, 2, 2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 3, 0, 2, 1, 0, 13, 0, 0, 0, 0,
+ 0, 4, 5, 6, 7, 8, 9, 20, 18, 19,
+ 0, 15, 0, 10, 22, 23, 21, 0, 0, 0,
+ 0, 14, 0, 16, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 17, 12, 0, 0, 0,
+ 11
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 2, 11, 12, 13, 14, 15, 21, 28,
+ 33, 16, 17, 18, 19
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -6
+static const yytype_int8 yypact[] =
+{
+ -6, 9, -3, -6, -2, -6, -1, 1, 3, 4,
+ 5, -6, -6, -6, -6, -6, -6, -6, -6, -6,
+ 0, -6, 7, -6, -6, -6, -6, 6, -5, 8,
+ 11, -6, 13, -6, 14, 10, 12, 15, 16, 17,
+ 18, 21, 19, 20, 22, -6, -6, 23, 24, 25,
+ -6
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -6, -6, -6, -6, -6, -6, -6, -6, -6, -6,
+ -6, -6, -6, -6, -6
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 4, 5, 6, 7, 8, 9, 10, 31, 32, 3,
+ 27, 20, 22, 23, 24, 25, 26, 29, 0, 0,
+ 30, 35, 34, 36, 37, 38, 39, 42, 43, 41,
+ 40, 44, 46, 48, 45, 0, 47, 50, 0, 49
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-6))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int8 yycheck[] =
+{
+ 3, 4, 5, 6, 7, 8, 9, 12, 13, 0,
+ 10, 13, 13, 12, 11, 11, 11, 10, -1, -1,
+ 14, 10, 14, 10, 10, 15, 14, 10, 10, 13,
+ 15, 10, 12, 10, 15, -1, 14, 12, -1, 15
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 17, 18, 0, 3, 4, 5, 6, 7, 8,
+ 9, 19, 20, 21, 22, 23, 27, 28, 29, 30,
+ 13, 24, 13, 12, 11, 11, 11, 10, 25, 10,
+ 14, 12, 13, 26, 14, 10, 10, 10, 15, 14,
+ 15, 13, 10, 10, 10, 15, 12, 14, 10, 15,
+ 12
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 10:
+/* Line 1787 of yacc.c */
+#line 74 "imap_cern.y"
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->default_url, (yyvsp[(2) - (2)].id));
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 11:
+/* Line 1787 of yacc.c */
+#line 83 "imap_cern.y"
+ {
+ gint x = (gint) (yyvsp[(3) - (12)].value);
+ gint y = (gint) (yyvsp[(5) - (12)].value);
+ gint width = (gint) fabs((yyvsp[(8) - (12)].value) - x);
+ gint height = (gint) fabs((yyvsp[(10) - (12)].value) - y);
+ current_object = create_rectangle(x, y, width, height);
+ object_set_url(current_object, (yyvsp[(12) - (12)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(12) - (12)].id));
+ }
+ break;
+
+ case 12:
+/* Line 1787 of yacc.c */
+#line 96 "imap_cern.y"
+ {
+ gint x = (gint) (yyvsp[(3) - (8)].value);
+ gint y = (gint) (yyvsp[(5) - (8)].value);
+ gint r = (gint) (yyvsp[(7) - (8)].value);
+ current_object = create_circle(x, y, r);
+ object_set_url(current_object, (yyvsp[(8) - (8)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(8) - (8)].id));
+ }
+ break;
+
+ case 13:
+/* Line 1787 of yacc.c */
+#line 107 "imap_cern.y"
+ {current_object = create_polygon(NULL);}
+ break;
+
+ case 14:
+/* Line 1787 of yacc.c */
+#line 108 "imap_cern.y"
+ {
+ object_set_url(current_object, (yyvsp[(4) - (4)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(4) - (4)].id));
+ }
+ break;
+
+ case 16:
+/* Line 1787 of yacc.c */
+#line 117 "imap_cern.y"
+ {
+ }
+ break;
+
+ case 17:
+/* Line 1787 of yacc.c */
+#line 122 "imap_cern.y"
+ {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GdkPoint *point = new_point((gint) (yyvsp[(2) - (5)].value), (gint) (yyvsp[(4) - (5)].value));
+ polygon->points = g_list_append(polygon->points,
+ (gpointer) point);
+ }
+ break;
+
+ case 21:
+/* Line 1787 of yacc.c */
+#line 136 "imap_cern.y"
+ {
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 22:
+/* Line 1787 of yacc.c */
+#line 142 "imap_cern.y"
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->author, (yyvsp[(2) - (2)].id));
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 23:
+/* Line 1787 of yacc.c */
+#line 150 "imap_cern.y"
+ {
+ MapInfo_t *info = get_map_info();
+ gchar *description;
+
+ description = g_strconcat(info->description, (yyvsp[(2) - (2)].id), "\n",
+ NULL);
+ g_strreplace(&info->description, description);
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 1569 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2048 of yacc.c */
+#line 162 "imap_cern.y"
+
+
+static void
+cern_error(char* s)
+{
+ extern FILE *cern_in;
+ cern_restart(cern_in);
+}
+
+gboolean
+load_cern(const char* filename)
+{
+ gboolean status;
+ extern FILE *cern_in;
+ cern_in = g_fopen(filename, "r");
+ if (cern_in) {
+ status = !cern_parse();
+ fclose(cern_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
+
diff --git a/plug-ins/imagemap/imap_cern_parse.h b/plug-ins/imagemap/imap_cern_parse.h
new file mode 100644
index 0000000..f46caff
--- /dev/null
+++ b/plug-ins/imagemap/imap_cern_parse.h
@@ -0,0 +1,110 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef CERN_Y_TAB_H
+# define CERN_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int cern_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ RECTANGLE = 258,
+ POLYGON = 259,
+ CIRCLE = 260,
+ DEFAULT = 261,
+ AUTHOR = 262,
+ DESCRIPTION = 263,
+ BEGIN_COMMENT = 264,
+ FLOAT = 265,
+ COMMENT = 266,
+ LINK = 267
+ };
+#endif
+/* Tokens. */
+#define RECTANGLE 258
+#define POLYGON 259
+#define CIRCLE 260
+#define DEFAULT 261
+#define AUTHOR 262
+#define DESCRIPTION 263
+#define BEGIN_COMMENT 264
+#define FLOAT 265
+#define COMMENT 266
+#define LINK 267
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2049 of yacc.c */
+#line 46 "imap_cern.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 2049 of yacc.c */
+#line 88 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE cern_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int cern_parse (void *YYPARSE_PARAM);
+#else
+int cern_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int cern_parse (void);
+#else
+int cern_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !CERN_Y_TAB_H */
diff --git a/plug-ins/imagemap/imap_circle.c b/plug-ins/imagemap/imap_circle.c
new file mode 100644
index 0000000..230b547
--- /dev/null
+++ b/plug-ins/imagemap/imap_circle.c
@@ -0,0 +1,405 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_main.h"
+#include "imap_misc.h"
+#include "imap_object_popup.h"
+#include "imap_stock.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static gboolean circle_is_valid(Object_t *obj);
+static Object_t *circle_clone(Object_t *obj);
+static void circle_assign(Object_t *obj, Object_t *des);
+static void circle_draw(Object_t* obj, cairo_t *cr);
+static void circle_draw_sashes(Object_t* obj, cairo_t *cr);
+static MoveSashFunc_t circle_near_sash(Object_t *obj, gint x, gint y);
+static gboolean circle_point_is_on(Object_t *obj, gint x, gint y);
+static void circle_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height);
+static void circle_resize(Object_t *obj, gint percentage_x, gint percentage_y);
+static void circle_move(Object_t *obj, gint dx, gint dy);
+static gpointer circle_create_info_widget(GtkWidget *frame);
+static void circle_fill_info_tab(Object_t *obj, gpointer data);
+static void circle_set_initial_focus(Object_t *obj, gpointer data);
+static void circle_update(Object_t* obj, gpointer data);
+static void circle_write_csim(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static void circle_write_cern(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static void circle_write_ncsa(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static const gchar* circle_get_stock_icon_name(void);
+
+static ObjectClass_t circle_class = {
+ N_("C_ircle"),
+ NULL, /* info_dialog */
+
+ circle_is_valid,
+ NULL, /* circle_destruct */
+ circle_clone,
+ circle_assign,
+ NULL, /* circle_normalize */
+ circle_draw,
+ circle_draw_sashes,
+ circle_near_sash,
+ circle_point_is_on,
+ circle_get_dimensions,
+ circle_resize,
+ circle_move,
+ circle_create_info_widget,
+ circle_fill_info_tab, /* circle_update_info_widget */
+ circle_fill_info_tab,
+ circle_set_initial_focus,
+ circle_update,
+ circle_write_csim,
+ circle_write_cern,
+ circle_write_ncsa,
+ object_do_popup,
+ circle_get_stock_icon_name
+};
+
+Object_t*
+create_circle(gint x, gint y, gint r)
+{
+ Circle_t *circle = g_new(Circle_t, 1);
+ circle->x = x;
+ circle->y = y;
+ circle->r = r;
+ return object_init(&circle->obj, &circle_class);
+}
+
+static gboolean
+circle_is_valid(Object_t *obj)
+{
+ return ObjectToCircle(obj)->r > 0;
+}
+
+static Object_t*
+circle_clone(Object_t *obj)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ Circle_t *clone = g_new(Circle_t, 1);
+
+ clone->x = circle->x;
+ clone->y = circle->y;
+ clone->r = circle->r;
+ return &clone->obj;
+}
+
+static void
+circle_assign(Object_t *obj, Object_t *des)
+{
+ Circle_t *src_circle = ObjectToCircle(obj);
+ Circle_t *des_circle = ObjectToCircle(des);
+ des_circle->x = src_circle->x;
+ des_circle->y = src_circle->y;
+ des_circle->r = src_circle->r;
+}
+
+static void
+circle_draw(Object_t *obj, cairo_t *cr)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ draw_circle(cr, circle->x, circle->y, circle->r);
+}
+
+static void
+circle_draw_sashes(Object_t *obj, cairo_t *cr)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ draw_sash(cr, circle->x - circle->r, circle->y - circle->r);
+ draw_sash(cr, circle->x + circle->r, circle->y - circle->r);
+ draw_sash(cr, circle->x - circle->r, circle->y + circle->r);
+ draw_sash(cr, circle->x + circle->r, circle->y + circle->r);
+}
+
+static gint sash_x;
+static gint sash_y;
+
+static void
+move_sash(Object_t *obj, gint dx, gint dy)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ gint rx, ry;
+ sash_x += dx;
+ sash_y += dy;
+
+ rx = abs(circle->x - sash_x);
+ ry = abs(circle->y - sash_y);
+ circle->r = (rx > ry) ? rx : ry;
+}
+
+static void
+circle_resize(Object_t *obj, gint percentage_x, gint percentage_y)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ circle->x = circle->x * percentage_x / 100;
+ circle->y = circle->y * percentage_y / 100;
+ circle->r = circle->r * ((percentage_x < percentage_y)
+ ? percentage_x : percentage_y) / 100;
+}
+
+static MoveSashFunc_t
+circle_near_sash(Object_t *obj, gint x, gint y)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ sash_x = x;
+ sash_y = y;
+ if (near_sash(circle->x - circle->r, circle->y - circle->r, x, y) ||
+ near_sash(circle->x + circle->r, circle->y - circle->r, x, y) ||
+ near_sash(circle->x - circle->r, circle->y + circle->r, x, y) ||
+ near_sash(circle->x + circle->r, circle->y + circle->r, x, y))
+ return move_sash;
+ return NULL;
+}
+
+static gboolean
+circle_point_is_on(Object_t *obj, gint x, gint y)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ x -= circle->x;
+ y -= circle->y;
+ return x * x + y * y <= circle->r * circle->r;
+}
+
+static void
+circle_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ *x = circle->x - circle->r;
+ *y = circle->y - circle->r;
+ *width = *height = 2 * circle->r;
+}
+
+static void
+circle_move(Object_t *obj, gint dx, gint dy)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ circle->x += dx;
+ circle->y += dy;
+}
+
+typedef struct {
+ Object_t *obj;
+ GtkWidget *x;
+ GtkWidget *y;
+ GtkWidget *r;
+} CircleProperties_t;
+
+static void
+x_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((CircleProperties_t*) data)->obj;
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToCircle(obj)->x = x;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+y_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((CircleProperties_t*) data)->obj;
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToCircle(obj)->y = y;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+r_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((CircleProperties_t*) data)->obj;
+ gint r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToCircle(obj)->r = r;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static gpointer
+circle_create_info_widget(GtkWidget *frame)
+{
+ CircleProperties_t *props = g_new(CircleProperties_t, 1);
+ GtkWidget *table, *label;
+ gint max_width = get_image_width();
+ gint max_height = get_image_height();
+
+ table = gtk_table_new(3, 3, FALSE);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_widget_show(table);
+
+ label = create_label_in_table(table, 0, 0, _("Center _x:"));
+ props->x = create_spin_button_in_table(table, label, 0, 1, 1, 0,
+ max_width - 1);
+ g_signal_connect(props->x, "value-changed",
+ G_CALLBACK (x_changed_cb), (gpointer) props);
+ create_label_in_table(table, 0, 2, _("pixels"));
+
+ label = create_label_in_table(table, 1, 0, _("Center _y:"));
+ props->y = create_spin_button_in_table(table, label, 1, 1, 1, 0,
+ max_height - 1);
+ g_signal_connect(props->y, "value-changed",
+ G_CALLBACK (y_changed_cb), (gpointer) props);
+ create_label_in_table(table, 1, 2, _("pixels"));
+
+ label = create_label_in_table(table, 2, 0, _("_Radius:"));
+ props->r = create_spin_button_in_table(table, label, 2, 1, 1, 1, G_MAXINT);
+ g_signal_connect(props->r, "value-changed",
+ G_CALLBACK (r_changed_cb), (gpointer) props);
+ create_label_in_table(table, 2, 2, _("pixels"));
+
+ return props;
+}
+
+static void
+circle_fill_info_tab(Object_t *obj, gpointer data)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ CircleProperties_t *props = (CircleProperties_t*) data;
+
+ props->obj = obj;
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), circle->x);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), circle->y);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->r), circle->r);
+}
+
+static void
+circle_set_initial_focus(Object_t *obj, gpointer data)
+{
+ CircleProperties_t *props = (CircleProperties_t*) data;
+ gtk_widget_grab_focus(props->x);
+}
+
+static void
+circle_update(Object_t* obj, gpointer data)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ CircleProperties_t *props = (CircleProperties_t*) data;
+
+ circle->x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->x));
+ circle->y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->y));
+ circle->r = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->r));
+}
+
+static void
+circle_write_csim(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ output(param, "\"circle\" coords=\"%d,%d,%d\"", circle->x, circle->y,
+ circle->r);
+}
+
+static void
+circle_write_cern(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ output(param, "circ (%d,%d) %d", circle->x, circle->y, circle->r);
+}
+
+static void
+circle_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+ output(param, "circle %s %d,%d %d,%d", obj->url,
+ circle->x, circle->y, circle->x, circle->y + circle->r);
+}
+
+static const gchar*
+circle_get_stock_icon_name(void)
+{
+ return IMAP_STOCK_CIRCLE;
+}
+
+static gint _start_x, _start_y;
+
+static Object_t*
+circle_factory_create_object1(gint x, gint y)
+{
+ _start_x = x;
+ _start_y = y;
+ return create_circle(x, y, 0);
+}
+
+static void
+circle_factory_set_xy1(Object_t *obj, guint state, gint x, gint y)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+
+ circle->x = (_start_x + x) / 2;
+ circle->y = (_start_y + y) / 2;
+ x -= _start_x;
+ y -= _start_y;
+ circle->r = (gint) sqrt(x * x + y * y) / 2;
+
+ main_set_dimension(circle->r, circle->r);
+}
+
+static ObjectFactory_t circle_factory1 = {
+ NULL, /* Object pointer */
+ NULL, /* Finish func */
+ NULL, /* Cancel func */
+ circle_factory_create_object1,
+ circle_factory_set_xy1
+};
+
+static Object_t*
+circle_factory_create_object2(gint x, gint y)
+{
+ return create_circle(x, y, 0);
+}
+
+static void
+circle_factory_set_xy2(Object_t *obj, guint state, gint x, gint y)
+{
+ Circle_t *circle = ObjectToCircle(obj);
+
+ x -= circle->x;
+ y -= circle->y;
+ circle->r = (gint) sqrt(x * x + y * y);
+
+ main_set_dimension(circle->r, circle->r);
+}
+
+static ObjectFactory_t circle_factory2 = {
+ NULL, /* Object pointer */
+ NULL, /* Finish func */
+ NULL, /* Cancel func */
+ circle_factory_create_object2,
+ circle_factory_set_xy2
+};
+
+ObjectFactory_t*
+get_circle_factory(guint state)
+{
+ return (state & GDK_SHIFT_MASK) ? &circle_factory1 : &circle_factory2;
+}
diff --git a/plug-ins/imagemap/imap_circle.h b/plug-ins/imagemap/imap_circle.h
new file mode 100644
index 0000000..f56263a
--- /dev/null
+++ b/plug-ins/imagemap/imap_circle.h
@@ -0,0 +1,40 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_CIRCLE_H
+#define _IMAP_CIRCLE_H
+
+#include "imap_object.h"
+
+typedef struct {
+ Object_t obj;
+ gint x;
+ gint y;
+ gint r;
+} Circle_t;
+
+#define ObjectToCircle(obj) ((Circle_t*) (obj))
+
+Object_t *create_circle(gint x, gint y, gint r);
+ObjectFactory_t *get_circle_factory(guint state);
+
+#endif /* _IMAP_CIRCLE_H */
diff --git a/plug-ins/imagemap/imap_cmd_clear.c b/plug-ins/imagemap/imap_cmd_clear.c
new file mode 100644
index 0000000..676e8b8
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_clear.c
@@ -0,0 +1,72 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t clear_command_execute(Command_t *parent);
+
+static CommandClass_t clear_command_class = {
+ NULL, /* clear_command_destruct */
+ clear_command_execute,
+ NULL, /* clear_command_undo */
+ NULL /* clear_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} ClearCommand_t;
+
+Command_t*
+clear_command_new(ObjectList_t *list)
+{
+ ClearCommand_t *command = g_new(ClearCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Clear"), &clear_command_class);
+}
+
+static void
+remove_one_object(Object_t *obj, gpointer data)
+{
+ ClearCommand_t *command = (ClearCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ delete_command_new(command->list, obj));
+}
+
+static CmdExecuteValue_t
+clear_command_execute(Command_t *parent)
+{
+ ClearCommand_t *command = (ClearCommand_t*) parent;
+ gpointer id;
+
+ id = object_list_add_remove_cb(command->list, remove_one_object, command);
+ object_list_delete_selected(command->list);
+ object_list_remove_remove_cb(command->list, id);
+
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_copy.c b/plug-ins/imagemap/imap_cmd_copy.c
new file mode 100644
index 0000000..453a5ee
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_copy.c
@@ -0,0 +1,71 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t copy_command_execute(Command_t *parent);
+static void copy_command_undo(Command_t *parent);
+
+static CommandClass_t copy_command_class = {
+ NULL, /* copy_command_destruct */
+ copy_command_execute,
+ copy_command_undo,
+ NULL /* copy_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ ObjectList_t *paste_buffer;
+} CopyCommand_t;
+
+Command_t*
+copy_command_new(ObjectList_t *list)
+{
+ CopyCommand_t *command = g_new(CopyCommand_t, 1);
+ command->list = list;
+ command->paste_buffer = NULL;
+ return command_init(&command->parent, _("Copy"), &copy_command_class);
+}
+
+static CmdExecuteValue_t
+copy_command_execute(Command_t *parent)
+{
+ CopyCommand_t *command = (CopyCommand_t*) parent;
+ command->paste_buffer = object_list_copy(command->paste_buffer,
+ get_paste_buffer());
+ object_list_copy_to_paste_buffer(command->list);
+ return CMD_APPEND;
+}
+
+static void
+copy_command_undo(Command_t *parent)
+{
+ CopyCommand_t *command = (CopyCommand_t*) parent;
+ object_list_copy(get_paste_buffer(), command->paste_buffer);
+}
diff --git a/plug-ins/imagemap/imap_cmd_copy_object.c b/plug-ins/imagemap/imap_cmd_copy_object.c
new file mode 100644
index 0000000..f59fd81
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_copy_object.c
@@ -0,0 +1,84 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void copy_object_command_destruct(Command_t *parent);
+static CmdExecuteValue_t copy_object_command_execute(Command_t *parent);
+static void copy_object_command_undo(Command_t *parent);
+
+static CommandClass_t copy_object_command_class = {
+ copy_object_command_destruct,
+ copy_object_command_execute,
+ copy_object_command_undo,
+ NULL /* copy_object_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Object_t *obj;
+ ObjectList_t *paste_buffer;
+} CopyObjectCommand_t;
+
+Command_t*
+copy_object_command_new(Object_t *obj)
+{
+ CopyObjectCommand_t *command = g_new(CopyObjectCommand_t, 1);
+ command->obj = object_ref(obj);
+ command->paste_buffer = NULL;
+ return command_init(&command->parent, _("Copy"),
+ &copy_object_command_class);
+}
+
+static void
+copy_object_command_destruct(Command_t *parent)
+{
+ CopyObjectCommand_t *command = (CopyObjectCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+copy_object_command_execute(Command_t *parent)
+{
+ CopyObjectCommand_t *command = (CopyObjectCommand_t*) parent;
+ ObjectList_t *paste_buffer = get_paste_buffer();
+
+ command->paste_buffer = object_list_copy(command->paste_buffer,
+ paste_buffer);
+ clear_paste_buffer();
+ object_list_append(paste_buffer, object_clone(command->obj));
+
+ return CMD_APPEND;
+}
+
+static void
+copy_object_command_undo(Command_t *parent)
+{
+ CopyObjectCommand_t *command = (CopyObjectCommand_t*) parent;
+ object_list_copy(get_paste_buffer(), command->paste_buffer);
+}
diff --git a/plug-ins/imagemap/imap_cmd_create.c b/plug-ins/imagemap/imap_cmd_create.c
new file mode 100644
index 0000000..49719d5
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_create.c
@@ -0,0 +1,82 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t create_command_execute(Command_t *parent);
+static void create_command_destruct(Command_t *parent);
+static void create_command_undo(Command_t *parent);
+
+static CommandClass_t create_command_class = {
+ create_command_destruct,
+ create_command_execute,
+ create_command_undo,
+ NULL /* create_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ Object_t *obj;
+ gboolean changed;
+} CreateCommand_t;
+
+Command_t*
+create_command_new(ObjectList_t *list, Object_t *obj)
+{
+ CreateCommand_t *command = g_new(CreateCommand_t, 1);
+ command->list = list;
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Create"), &create_command_class);
+}
+
+static void
+create_command_destruct(Command_t *parent)
+{
+ CreateCommand_t *command = (CreateCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+create_command_execute(Command_t *parent)
+{
+ CreateCommand_t *command = (CreateCommand_t*) parent;
+ command->changed = object_list_get_changed(command->list);
+ object_list_append(command->list, object_ref(command->obj));
+ return CMD_APPEND;
+}
+
+static void
+create_command_undo(Command_t *parent)
+{
+ CreateCommand_t *command = (CreateCommand_t*) parent;
+ object_list_remove(command->list, command->obj);
+ object_list_set_changed(command->list, command->changed);
+}
diff --git a/plug-ins/imagemap/imap_cmd_cut.c b/plug-ins/imagemap/imap_cmd_cut.c
new file mode 100644
index 0000000..0bf06c1
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_cut.c
@@ -0,0 +1,92 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void cut_command_destruct(Command_t *parent);
+static CmdExecuteValue_t cut_command_execute(Command_t *parent);
+static void cut_command_undo(Command_t *parent);
+
+static CommandClass_t cut_command_class = {
+ cut_command_destruct,
+ cut_command_execute,
+ cut_command_undo,
+ NULL /* cut_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ ObjectList_t *paste_buffer;
+} CutCommand_t;
+
+Command_t*
+cut_command_new(ObjectList_t *list)
+{
+ CutCommand_t *command = g_new(CutCommand_t, 1);
+ command->list = list;
+ command->paste_buffer = NULL;
+ return command_init(&command->parent, _("Cut"), &cut_command_class);
+}
+
+static void
+cut_command_destruct(Command_t *parent)
+{
+ CutCommand_t *command = (CutCommand_t*) parent;
+ object_list_destruct(command->paste_buffer);
+}
+
+static void
+remove_one_object(Object_t *obj, gpointer data)
+{
+ CutCommand_t *command = (CutCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ delete_command_new(command->list, obj));
+}
+
+static CmdExecuteValue_t
+cut_command_execute(Command_t *parent)
+{
+ CutCommand_t *command = (CutCommand_t*) parent;
+ gpointer id;
+
+ command->paste_buffer = object_list_copy(command->paste_buffer,
+ get_paste_buffer());
+ id = object_list_add_remove_cb(command->list, remove_one_object, command);
+ object_list_cut(command->list);
+ object_list_remove_remove_cb(command->list, id);
+
+ return CMD_APPEND;
+}
+
+static void
+cut_command_undo(Command_t *parent)
+{
+ CutCommand_t *command = (CutCommand_t*) parent;
+ object_list_copy(get_paste_buffer(), command->paste_buffer);
+}
diff --git a/plug-ins/imagemap/imap_cmd_cut_object.c b/plug-ins/imagemap/imap_cmd_cut_object.c
new file mode 100644
index 0000000..780c4f8
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_cut_object.c
@@ -0,0 +1,62 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t cut_object_command_execute(Command_t *parent);
+
+static CommandClass_t cut_object_command_class = {
+ NULL, /* cut_object_command_destruct */
+ cut_object_command_execute,
+ NULL, /* cut_object_command_undo */
+ NULL /* cut_object_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+} CutObjectCommand_t;
+
+Command_t*
+cut_object_command_new(Object_t *obj)
+{
+ CutObjectCommand_t *command = g_new(CutObjectCommand_t, 1);
+ Command_t *parent;
+
+ parent = command_init(&command->parent, _("Cut"),
+ &cut_object_command_class);
+ command_add_subcommand(parent, copy_object_command_new(obj));
+ command_add_subcommand(parent, delete_command_new(obj->list, obj));
+
+ return parent;
+}
+
+static CmdExecuteValue_t
+cut_object_command_execute(Command_t *parent)
+{
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_delete.c b/plug-ins/imagemap/imap_cmd_delete.c
new file mode 100644
index 0000000..6c85984
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_delete.c
@@ -0,0 +1,83 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void delete_command_destruct(Command_t *parent);
+static CmdExecuteValue_t delete_command_execute(Command_t *parent);
+static void delete_command_undo(Command_t *parent);
+
+static CommandClass_t delete_command_class = {
+ delete_command_destruct,
+ delete_command_execute,
+ delete_command_undo,
+ NULL /* delete_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ Object_t *obj;
+ gint position;
+ gboolean changed;
+} DeleteCommand_t;
+
+Command_t*
+delete_command_new(ObjectList_t *list, Object_t *obj)
+{
+ DeleteCommand_t *command = g_new(DeleteCommand_t, 1);
+ command->list = list;
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Delete"),
+ &delete_command_class);
+}
+
+static void
+delete_command_destruct(Command_t *parent)
+{
+ DeleteCommand_t *command = (DeleteCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+delete_command_execute(Command_t *parent)
+{
+ DeleteCommand_t *command = (DeleteCommand_t*) parent;
+ command->changed = object_list_get_changed(command->list);
+ command->position = object_get_position_in_list(command->obj);
+ object_list_remove(command->list, command->obj);
+ return CMD_APPEND;
+}
+
+static void
+delete_command_undo(Command_t *parent)
+{
+ DeleteCommand_t *command = (DeleteCommand_t*) parent;
+ object_list_insert(command->list, command->position, command->obj);
+ object_list_set_changed(command->list, command->changed);
+}
diff --git a/plug-ins/imagemap/imap_cmd_delete_point.c b/plug-ins/imagemap/imap_cmd_delete_point.c
new file mode 100644
index 0000000..1dd6092
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_delete_point.c
@@ -0,0 +1,86 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_polygon.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t delete_point_command_execute(Command_t *parent);
+static void delete_point_command_undo(Command_t *parent);
+
+static CommandClass_t delete_point_command_class = {
+ NULL, /* delete_point_command_destruct */
+ delete_point_command_execute,
+ delete_point_command_undo,
+ NULL /* delete_point_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Polygon_t *polygon;
+ GdkPoint *point;
+ GdkPoint copy;
+ gint position;
+} DeletePointCommand_t;
+
+Command_t*
+delete_point_command_new(Object_t *obj, GdkPoint *point)
+{
+ DeletePointCommand_t *command = g_new(DeletePointCommand_t, 1);
+
+ command->polygon = ObjectToPolygon(obj);
+ command->point = point;
+ command->copy = *point;
+ command->position = g_list_index(command->polygon->points,
+ (gpointer) point);
+ return command_init(&command->parent, _("Delete Point"),
+ &delete_point_command_class);
+}
+
+static CmdExecuteValue_t
+delete_point_command_execute(Command_t *parent)
+{
+ DeletePointCommand_t *command = (DeletePointCommand_t*) parent;
+ Polygon_t *polygon = command->polygon;
+ GList *p = g_list_find(polygon->points, (gpointer) command->point);
+
+ g_free(p->data);
+ polygon->points = g_list_remove_link(polygon->points, p);
+ return CMD_APPEND;
+}
+
+static void
+delete_point_command_undo(Command_t *parent)
+{
+ DeletePointCommand_t *command = (DeletePointCommand_t*) parent;
+ Polygon_t *polygon = command->polygon;
+ GdkPoint *point = &command->copy;
+
+ command->point = new_point(point->x, point->y);
+ polygon->points = g_list_insert(polygon->points, (gpointer) command->point,
+ command->position);
+}
diff --git a/plug-ins/imagemap/imap_cmd_edit_object.c b/plug-ins/imagemap/imap_cmd_edit_object.c
new file mode 100644
index 0000000..d2f0c39
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_edit_object.c
@@ -0,0 +1,73 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void edit_object_command_destruct(Command_t *parent);
+static void edit_object_command_undo(Command_t *parent);
+
+static CommandClass_t edit_object_command_class = {
+ edit_object_command_destruct,
+ NULL, /* edit_object_command_execute */
+ edit_object_command_undo,
+ edit_object_command_undo
+};
+
+typedef struct {
+ Command_t parent;
+ Object_t *obj;
+ Object_t *copy;
+} EditObjectCommand_t;
+
+Command_t*
+edit_object_command_new(Object_t *obj)
+{
+ EditObjectCommand_t *command = g_new(EditObjectCommand_t, 1);
+ command->obj = object_ref(obj);
+ command->copy = object_clone(obj);
+ return command_init(&command->parent, _("Edit Object"),
+ &edit_object_command_class);
+}
+
+static void
+edit_object_command_destruct(Command_t *parent)
+{
+ EditObjectCommand_t *command = (EditObjectCommand_t*) parent;
+ object_unref(command->copy);
+ object_unref(command->obj);
+}
+
+static void
+edit_object_command_undo(Command_t *parent)
+{
+ EditObjectCommand_t *command = (EditObjectCommand_t*) parent;
+ Object_t *copy = object_clone(command->obj);
+
+ object_assign(command->copy, command->obj);
+ object_assign(copy, command->copy);
+}
diff --git a/plug-ins/imagemap/imap_cmd_gimp_guides.c b/plug-ins/imagemap/imap_cmd_gimp_guides.c
new file mode 100644
index 0000000..3f8fdd2
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_gimp_guides.c
@@ -0,0 +1,260 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "libgimp/gimp.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "imap_commands.h"
+#include "imap_default_dialog.h"
+#include "imap_main.h"
+#include "imap_rectangle.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+typedef struct {
+ DefaultDialog_t *dialog;
+
+ ObjectList_t *list;
+ gint32 drawable_id;
+
+ GtkWidget *alternate;
+ GtkWidget *all;
+ GtkWidget *left_border;
+ GtkWidget *right_border;
+ GtkWidget *upper_border;
+ GtkWidget *lower_border;
+ GtkWidget *url;
+} GimpGuidesDialog_t;
+
+static gint
+guide_sort_func(gconstpointer a, gconstpointer b)
+{
+ return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
+}
+
+static void
+gimp_guides_ok_cb(gpointer data)
+{
+ GimpGuidesDialog_t *param = (GimpGuidesDialog_t*) data;
+ gint guide_num;
+ GSList *hguides, *hg;
+ GSList *vguides, *vg;
+ gboolean all;
+ const gchar *url;
+ gint32 image_ID = gimp_item_get_image (param->drawable_id);
+
+ /* First get some dialog values */
+
+ all = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->all));
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->left_border)))
+ vguides = g_slist_append(NULL, GINT_TO_POINTER(0));
+ else
+ vguides = NULL;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->right_border)))
+ vguides = g_slist_append(vguides,
+ GINT_TO_POINTER(gimp_image_width(image_ID)));
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->upper_border)))
+ hguides = g_slist_append(NULL, GINT_TO_POINTER(0));
+ else
+ hguides = NULL;
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->lower_border)))
+ hguides = g_slist_append(hguides,
+ GINT_TO_POINTER(gimp_image_height(image_ID)));
+
+ url = gtk_entry_get_text(GTK_ENTRY(param->url));
+
+ /* Next get all the GIMP guides */
+
+ guide_num = gimp_image_find_next_guide(image_ID, 0);
+
+ while (guide_num > 0) {
+ gint position = gimp_image_get_guide_position(image_ID, guide_num);
+
+ if (gimp_image_get_guide_orientation(image_ID, guide_num)
+ == GIMP_ORIENTATION_HORIZONTAL) {
+ hguides = g_slist_insert_sorted(hguides, GINT_TO_POINTER(position),
+ guide_sort_func);
+ } else { /* GIMP_ORIENTATION_VERTICAL */
+ vguides = g_slist_insert_sorted(vguides, GINT_TO_POINTER(position),
+ guide_sort_func);
+ }
+ guide_num = gimp_image_find_next_guide(image_ID, guide_num);
+ }
+
+ /* Create the areas */
+
+ subcommand_start(_("Use Gimp Guides"));
+
+ for (hg = hguides; hg && hg->next;
+ hg = (all) ? hg->next : hg->next->next) {
+ gint y = GPOINTER_TO_INT(hg->data);
+ gint height = GPOINTER_TO_INT(hg->next->data) - y;
+ for (vg = vguides; vg && vg->next;
+ vg = (all) ? vg->next : vg->next->next) {
+ gint x = GPOINTER_TO_INT(vg->data);
+ gint width = GPOINTER_TO_INT(vg->next->data) - x;
+ Object_t *obj = create_rectangle(x, y, width, height);
+ Command_t *command = create_command_new(param->list, obj);
+
+ object_set_url(obj, url);
+ command_execute(command);
+ }
+ }
+
+ subcommand_end();
+ preview_redraw();
+}
+
+static GimpGuidesDialog_t*
+make_gimp_guides_dialog(void)
+{
+ GimpGuidesDialog_t *data = g_new(GimpGuidesDialog_t, 1);
+ DefaultDialog_t *dialog;
+ GtkWidget *table, *frame, *hbox, *vbox;
+ GtkWidget *label;
+
+ dialog = data->dialog = make_default_dialog(_("Use Gimp Guides"));
+ default_dialog_set_ok_cb(dialog, gimp_guides_ok_cb, data);
+ table = default_dialog_add_table(dialog, 3, 2);
+
+ frame = gimp_frame_new(_("Create"));
+ gtk_widget_show(frame);
+ gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 1, 0, 1);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+
+ data->alternate =
+ gtk_radio_button_new_with_mnemonic_from_widget(NULL, _("Al_ternate"));
+ gtk_box_pack_start(GTK_BOX(hbox), data->alternate, FALSE, FALSE, 0);
+ gtk_widget_show(data->alternate);
+
+ data->all = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(data->alternate), _("A_ll"));
+ gtk_box_pack_start(GTK_BOX(hbox), data->all, FALSE, FALSE, 0);
+ gtk_widget_show(data->all);
+
+ frame = gimp_frame_new(_("Add Additional Guides"));
+ gtk_widget_show(frame);
+ gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 1, 1, 2);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add(GTK_CONTAINER(frame), vbox);
+ gtk_widget_show(vbox);
+
+ data->left_border = gtk_check_button_new_with_mnemonic(_("L_eft border"));
+ gtk_container_add(GTK_CONTAINER(vbox), data->left_border);
+ gtk_widget_show(data->left_border);
+
+ data->right_border = gtk_check_button_new_with_mnemonic(_("_Right border"));
+ gtk_container_add(GTK_CONTAINER(vbox), data->right_border);
+ gtk_widget_show(data->right_border);
+
+ data->upper_border = gtk_check_button_new_with_mnemonic(_("_Upper border"));
+ gtk_container_add(GTK_CONTAINER(vbox), data->upper_border);
+ gtk_widget_show(data->upper_border);
+
+ data->lower_border = gtk_check_button_new_with_mnemonic(_("Lo_wer border"));
+ gtk_container_add(GTK_CONTAINER(vbox), data->lower_border);
+ gtk_widget_show(data->lower_border);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_table_attach_defaults(GTK_TABLE(table), hbox, 0, 2, 2, 3);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new_with_mnemonic(_("_Base URL:"));
+ gtk_widget_show(label);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ data->url = gtk_entry_new();
+ gtk_container_add(GTK_CONTAINER(hbox), data->url);
+ gtk_widget_show(data->url);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), data->url);
+
+ return data;
+}
+
+static void
+init_gimp_guides_dialog(GimpGuidesDialog_t *dialog, ObjectList_t *list,
+ gint32 drawable_id)
+{
+ dialog->list = list;
+ dialog->drawable_id = drawable_id;
+}
+
+static void
+do_create_gimp_guides_dialog(ObjectList_t *list, gint32 drawable_id)
+{
+ static GimpGuidesDialog_t *dialog;
+
+ if (!dialog)
+ dialog = make_gimp_guides_dialog();
+
+ init_gimp_guides_dialog(dialog, list, drawable_id);
+ default_dialog_show(dialog->dialog);
+}
+
+static CmdExecuteValue_t gimp_guides_command_execute(Command_t *parent);
+
+static CommandClass_t gimp_guides_command_class = {
+ NULL, /* guides_command_destruct */
+ gimp_guides_command_execute,
+ NULL, /* guides_command_undo */
+ NULL /* guides_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ gint32 drawable_id;
+} GimpGuidesCommand_t;
+
+Command_t*
+gimp_guides_command_new(ObjectList_t *list, gint32 drawable_id)
+{
+ GimpGuidesCommand_t *command = g_new(GimpGuidesCommand_t, 1);
+ command->list = list;
+ command->drawable_id = drawable_id;
+ return command_init(&command->parent, _("Use Gimp Guides"),
+ &gimp_guides_command_class);
+}
+
+static CmdExecuteValue_t
+gimp_guides_command_execute(Command_t *parent)
+{
+ GimpGuidesCommand_t *command = (GimpGuidesCommand_t*) parent;
+ do_create_gimp_guides_dialog(command->list, command->drawable_id);
+ return CMD_DESTRUCT;
+}
diff --git a/plug-ins/imagemap/imap_cmd_guides.c b/plug-ins/imagemap/imap_cmd_guides.c
new file mode 100644
index 0000000..aa9667f
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_guides.c
@@ -0,0 +1,279 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 "libgimp/gimpui.h"
+
+#include "imap_commands.h"
+#include "imap_default_dialog.h"
+#include "imap_main.h"
+#include "imap_rectangle.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+typedef struct {
+ DefaultDialog_t *dialog;
+ GtkWidget *image_dimensions;
+ GtkWidget *guide_bounds;
+ GtkWidget *width;
+ GtkWidget *height;
+ GtkWidget *left;
+ GtkWidget *top;
+ GtkWidget *horz_spacing;
+ GtkWidget *vert_spacing;
+ GtkWidget *no_across;
+ GtkWidget *no_down;
+ GtkWidget *base_url;
+
+ ObjectList_t *list;
+} GuidesDialog_t;
+
+static void
+guides_ok_cb(gpointer data)
+{
+ GuidesDialog_t *param = (GuidesDialog_t*) data;
+ gint y;
+ int i, j;
+ gint width, height, left, top, hspace, vspace, rows, cols;
+
+ width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->width));
+ height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->height));
+ left = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->left));
+ top = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->top));
+ hspace = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->horz_spacing));
+ vspace = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->vert_spacing));
+ rows = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->no_down));
+ cols = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->no_across));
+
+ subcommand_start(_("Create Guides"));
+ y = top;
+ for (i = 0; i < rows; i++) {
+ gint x = left;
+ for (j = 0; j < cols; j++) {
+ Object_t *obj = create_rectangle(x, y, width, height);
+ Command_t *command = create_command_new(param->list, obj);
+
+ object_set_url(obj, gtk_entry_get_text(GTK_ENTRY(param->base_url)));
+ command_execute(command);
+ x += width + hspace;
+ }
+ y += height + vspace;
+ }
+ subcommand_end();
+}
+
+static void
+recalc_bounds(GtkWidget *widget, gpointer data)
+{
+ GuidesDialog_t *param = (GuidesDialog_t*) data;
+ gint width, height, left, top, hspace, vspace, rows, cols;
+ gint bound_w, bound_h;
+ gchar *bounds;
+
+ width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->width));
+ height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->height));
+ left = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->left));
+ top = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->top));
+ hspace = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->horz_spacing));
+ vspace = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->vert_spacing));
+ rows = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->no_down));
+ cols = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->no_across));
+
+ bound_w = (width + hspace) * cols - hspace;
+ bound_h = (height + vspace) * rows - vspace;
+
+ bounds = g_strdup_printf (_("Resulting Guide Bounds: %d,%d to %d,%d (%d areas)"),
+ left, top, left + bound_w, top + bound_h, rows * cols);
+ if (left + bound_w > get_image_width() ||
+ top + bound_h > get_image_height())
+ {
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (param->dialog->dialog),
+ GTK_RESPONSE_OK, FALSE);
+ }
+ else
+ {
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (param->dialog->dialog),
+ GTK_RESPONSE_OK, TRUE);
+ }
+
+ gtk_label_set_text(GTK_LABEL(param->guide_bounds), bounds);
+ g_free (bounds);
+}
+
+static GuidesDialog_t*
+make_guides_dialog (void)
+{
+ GuidesDialog_t *data = g_new(GuidesDialog_t, 1);
+ DefaultDialog_t *dialog;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *hbox;
+
+ dialog = data->dialog = make_default_dialog(_("Create Guides"));
+ default_dialog_set_ok_cb (dialog, guides_ok_cb, data);
+
+ hbox = gimp_hint_box_new (
+ _("Guides are pre-defined rectangles covering the image. You define "
+ "them by their width, height, and spacing from each other. This "
+ "allows you to rapidly create the most common image map type - "
+ "image collection of \"thumbnails\", suitable for navigation bars."));
+ gtk_box_pack_start (GTK_BOX (dialog->vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ data->image_dimensions = gtk_label_new ("");
+ gtk_label_set_xalign (GTK_LABEL (data->image_dimensions), 0.0);
+ gtk_box_pack_start (GTK_BOX (dialog->vbox),
+ data->image_dimensions, FALSE, FALSE, 0);
+ gtk_widget_show (data->image_dimensions);
+
+ data->guide_bounds = gtk_label_new ("");
+ gtk_label_set_xalign (GTK_LABEL (data->guide_bounds), 0.0);
+ gtk_box_pack_start (GTK_BOX (dialog->vbox),
+ data->guide_bounds, FALSE, FALSE, 0);
+ gtk_widget_show (data->guide_bounds);
+
+ table = default_dialog_add_table (dialog, 4, 4);
+
+ label = create_label_in_table (table, 0, 0, _("_Width:"));
+ data->width = create_spin_button_in_table (table, label, 0, 1, 32, 1, 100);
+ g_signal_connect (data->width, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table(table, 0, 2, _("_Left start at:"));
+ data->left = create_spin_button_in_table (table, label, 0, 3, 0, 0, 100);
+ g_signal_connect (data->left, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table(table, 1, 0, _("_Height:"));
+ data->height = create_spin_button_in_table (table, label, 1, 1, 32, 1, 100);
+ g_signal_connect (data->height, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table (table, 1, 2, _("_Top start at:"));
+ data->top = create_spin_button_in_table (table, label, 1, 3, 0, 0, 100);
+ g_signal_connect (data->top, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table (table, 2, 0, _("_Horz. spacing:"));
+ data->horz_spacing = create_spin_button_in_table (table, label, 2, 1, 0, 0,
+ 100);
+ g_signal_connect (data->horz_spacing, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table(table, 2, 2, _("_No. across:"));
+ data->no_across = create_spin_button_in_table(table, label, 2, 3, 0, 0,
+ 100);
+ g_signal_connect (data->no_across, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table(table, 3, 0, _("_Vert. spacing:"));
+ data->vert_spacing = create_spin_button_in_table(table, label, 3, 1, 0, 0,
+ 100);
+ g_signal_connect (data->vert_spacing, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ label = create_label_in_table(table, 3, 2, _("No. _down:"));
+ data->no_down = create_spin_button_in_table (table, label, 3, 3, 0, 0, 100);
+ g_signal_connect (data->no_down, "changed",
+ G_CALLBACK(recalc_bounds), (gpointer) data);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (dialog->vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show(hbox);
+
+ label = gtk_label_new_with_mnemonic(_("Base _URL:"));
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+
+ data->base_url = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), data->base_url, TRUE, TRUE, 0);
+ gtk_widget_show(data->base_url);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), data->base_url);
+
+ return data;
+}
+
+static void
+init_guides_dialog(GuidesDialog_t *dialog, ObjectList_t *list)
+{
+ gchar *dimension;
+
+ dialog->list = list;
+ dimension = g_strdup_printf (_("Image dimensions: %d × %d"),
+ get_image_width(),
+ get_image_height());
+ gtk_label_set_text (GTK_LABEL(dialog->image_dimensions), dimension);
+ g_free (dimension);
+ gtk_label_set_text (GTK_LABEL(dialog->guide_bounds),
+ _("Resulting Guide Bounds: 0,0 to 0,0 (0 areas)"));
+ gtk_widget_grab_focus (dialog->width);
+}
+
+static void
+do_create_guides_dialog_local (ObjectList_t *list)
+{
+ static GuidesDialog_t *dialog;
+
+ if (!dialog)
+ dialog = make_guides_dialog();
+
+ init_guides_dialog(dialog, list);
+ default_dialog_show(dialog->dialog);
+}
+
+static CmdExecuteValue_t guides_command_execute(Command_t *parent);
+
+static CommandClass_t guides_command_class = {
+ NULL, /* guides_command_destruct */
+ guides_command_execute,
+ NULL, /* guides_command_undo */
+ NULL /* guides_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} GuidesCommand_t;
+
+Command_t*
+guides_command_new(ObjectList_t *list)
+{
+ GuidesCommand_t *command = g_new(GuidesCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Guides"), &guides_command_class);
+}
+
+static CmdExecuteValue_t
+guides_command_execute(Command_t *parent)
+{
+ GuidesCommand_t *command = (GuidesCommand_t*) parent;
+ do_create_guides_dialog_local (command->list);
+ return CMD_DESTRUCT;
+}
diff --git a/plug-ins/imagemap/imap_cmd_insert_point.c b/plug-ins/imagemap/imap_cmd_insert_point.c
new file mode 100644
index 0000000..ad887d3
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_insert_point.c
@@ -0,0 +1,96 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t insert_point_command_execute(Command_t *parent);
+static void insert_point_command_undo(Command_t *parent);
+
+static CommandClass_t insert_point_command_class = {
+ NULL, /* insert_point_command_destruct */
+ insert_point_command_execute,
+ insert_point_command_undo,
+ NULL /* insert_point_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Polygon_t *polygon;
+ gint x;
+ gint y;
+ gint edge;
+ gint position;
+} InsertPointCommand_t;
+
+Command_t*
+insert_point_command_new(Object_t *obj, gint x, gint y, gint edge)
+{
+ InsertPointCommand_t *command = g_new(InsertPointCommand_t, 1);
+
+ command->polygon = ObjectToPolygon(obj);
+ command->x = x;
+ command->y = y;
+ command->edge = edge;
+ return command_init(&command->parent, _("Insert Point"),
+ &insert_point_command_class);
+}
+
+static CmdExecuteValue_t
+insert_point_command_execute(Command_t *parent)
+{
+ InsertPointCommand_t *command = (InsertPointCommand_t*) parent;
+ Polygon_t *polygon = command->polygon;
+
+ GdkPoint *point = new_point(command->x, command->y);
+
+ if (g_list_length(polygon->points) == command->edge - 1) {
+ polygon->points = g_list_append(polygon->points, (gpointer) point);
+ command->position = command->edge - 1;
+ } else {
+ polygon->points = g_list_insert(polygon->points, (gpointer) point,
+ command->edge);
+ command->position = command->edge;
+ }
+ preview_redraw();
+
+ return CMD_APPEND;
+}
+
+static void
+insert_point_command_undo(Command_t *parent)
+{
+ InsertPointCommand_t *command = (InsertPointCommand_t*) parent;
+ Polygon_t *polygon = command->polygon;
+ GList *p = g_list_nth(polygon->points, command->position);
+
+ g_free(p->data);
+ polygon->points = g_list_remove_link(polygon->points, p);
+ preview_redraw(); /* Fix me! */
+}
diff --git a/plug-ins/imagemap/imap_cmd_move.c b/plug-ins/imagemap/imap_cmd_move.c
new file mode 100644
index 0000000..491b12d
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move.c
@@ -0,0 +1,166 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "libgimp/gimp.h"
+
+#include "imap_commands.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void move_command_destruct(Command_t *parent);
+static CmdExecuteValue_t move_command_execute(Command_t *parent);
+
+static CommandClass_t move_command_class = {
+ move_command_destruct,
+ move_command_execute,
+ NULL, /* move_command_undo */
+ NULL /* move_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ PreferencesData_t *preferences;
+ Preview_t *preview;
+ Object_t *obj;
+ gint start_x;
+ gint start_y;
+ gint obj_start_x;
+ gint obj_start_y;
+ gint obj_x;
+ gint obj_y;
+ gint obj_width;
+ gint obj_height;
+
+ gint image_width;
+ gint image_height;
+
+ GdkCursorType cursor; /* Remember previous cursor */
+ gboolean moved_first_time;
+} MoveCommand_t;
+
+Command_t*
+move_command_new(Preview_t *preview, Object_t *obj, gint x, gint y)
+{
+ MoveCommand_t *command = g_new(MoveCommand_t, 1);
+
+ command->preferences = get_preferences();
+ command->preview = preview;
+ command->obj = object_ref(obj);
+ command->start_x = x;
+ command->start_y = y;
+ object_get_dimensions(obj, &command->obj_x, &command->obj_y,
+ &command->obj_width, &command->obj_height);
+ command->obj_start_x = command->obj_x;
+ command->obj_start_y = command->obj_y;
+
+ command->image_width = get_image_width();
+ command->image_height = get_image_height();
+
+ command->moved_first_time = TRUE;
+
+ return command_init(&command->parent, _("Move"), &move_command_class);
+}
+
+static void
+move_command_destruct(Command_t *parent)
+{
+ MoveCommand_t *command = (MoveCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static void
+button_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+ MoveCommand_t *command = (MoveCommand_t*) data;
+ Object_t *obj = command->obj;
+ gint dx = get_real_coord((gint) event->x) - command->start_x;
+ gint dy = get_real_coord((gint) event->y) - command->start_y;
+
+ if (command->moved_first_time) {
+ command->moved_first_time = FALSE;
+ command->cursor = preview_set_cursor(command->preview, GDK_FLEUR);
+ hide_url();
+ }
+
+ if (command->obj_x + dx < 0)
+ dx = -command->obj_x;
+ if (command->obj_x + command->obj_width + dx > command->image_width)
+ dx = command->image_width - command->obj_width - command->obj_x;
+ if (command->obj_y + dy < 0)
+ dy = -command->obj_y;
+ if (command->obj_y + command->obj_height + dy > command->image_height)
+ dy = command->image_height - command->obj_height - command->obj_y;
+
+ if (dx || dy) {
+
+ command->start_x = get_real_coord((gint) event->x);
+ command->start_y = get_real_coord((gint) event->y);
+ command->obj_x += dx;
+ command->obj_y += dy;
+
+ object_move(obj, dx, dy);
+
+ preview_redraw ();
+ }
+}
+
+static void
+button_release(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ MoveCommand_t *command = (MoveCommand_t*) data;
+
+ g_signal_handlers_disconnect_by_func (widget,
+ button_motion, data);
+ g_signal_handlers_disconnect_by_func (widget,
+ button_release, data);
+
+ if (!command->moved_first_time) {
+ preview_set_cursor(command->preview, command->cursor);
+ show_url();
+ }
+ command->obj_x -= command->obj_start_x;
+ command->obj_y -= command->obj_start_y;
+ if (command->obj_x || command->obj_y)
+ command_list_add(object_move_command_new(command->obj, command->obj_x,
+ command->obj_y));
+
+ /* preview_thaw(); */
+}
+
+static CmdExecuteValue_t
+move_command_execute(Command_t *parent)
+{
+ MoveCommand_t *command = (MoveCommand_t*) parent;
+ GtkWidget *widget = command->preview->preview;
+
+ /* preview_freeze(); */
+ g_signal_connect(widget, "button-release-event",
+ G_CALLBACK (button_release), command);
+ g_signal_connect(widget, "motion-notify-event",
+ G_CALLBACK (button_motion), command);
+ return CMD_DESTRUCT;
+}
diff --git a/plug-ins/imagemap/imap_cmd_move_down.c b/plug-ins/imagemap/imap_cmd_move_down.c
new file mode 100644
index 0000000..401e597
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move_down.c
@@ -0,0 +1,82 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t move_down_command_execute(Command_t *parent);
+
+static CommandClass_t move_down_command_class = {
+ NULL, /* move_down_command_destruct */
+ move_down_command_execute,
+ NULL, /* move_down_command_undo */
+ NULL /* move_down_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ gboolean add;
+} MoveDownCommand_t;
+
+Command_t*
+move_down_command_new(ObjectList_t *list)
+{
+ MoveDownCommand_t *command = g_new(MoveDownCommand_t, 1);
+ command->list = list;
+ command->add = FALSE;
+ return command_init(&command->parent, _("Move Down"),
+ &move_down_command_class);
+}
+
+static void
+move_down_one_object(Object_t *obj, gpointer data)
+{
+ MoveDownCommand_t *command = (MoveDownCommand_t*) data;
+
+ if (command->add) {
+ command_add_subcommand(&command->parent,
+ object_down_command_new(command->list, obj));
+ command->add = FALSE;
+ }
+ else {
+ command->add = TRUE;
+ }
+}
+
+static CmdExecuteValue_t
+move_down_command_execute(Command_t *parent)
+{
+ MoveDownCommand_t *command = (MoveDownCommand_t*) parent;
+ gpointer id;
+
+ id = object_list_add_move_cb(command->list, move_down_one_object, command);
+ object_list_move_selected_down(command->list);
+ object_list_remove_move_cb(command->list, id);
+
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_move_sash.c b/plug-ins/imagemap/imap_cmd_move_sash.c
new file mode 100644
index 0000000..85c1db8
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move_sash.c
@@ -0,0 +1,150 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void move_sash_command_destruct(Command_t *command);
+static CmdExecuteValue_t move_sash_command_execute(Command_t *command);
+static void move_sash_command_redo(Command_t *command);
+
+static CommandClass_t move_sash_command_class = {
+ move_sash_command_destruct,
+ move_sash_command_execute,
+ NULL /*undo*/,
+ move_sash_command_redo
+};
+
+typedef struct {
+ Command_t parent;
+ GtkWidget *widget;
+ Object_t *obj;
+ gint x;
+ gint y;
+ gint image_width;
+ gint image_height;
+ MoveSashFunc_t sash_func;
+} MoveSashCommand_t;
+
+Command_t*
+move_sash_command_new(GtkWidget *widget, Object_t *obj,
+ gint x, gint y, MoveSashFunc_t sash_func)
+{
+ MoveSashCommand_t *command = g_new(MoveSashCommand_t, 1);
+ Command_t *parent;
+
+ command->widget = widget;
+ command->obj = object_ref(obj);
+ command->x = x;
+ command->y = y;
+ command->image_width = get_image_width();
+ command->image_height = get_image_height();
+ command->sash_func = sash_func;
+
+ parent = command_init(&command->parent, _("Move Sash"),
+ &move_sash_command_class);
+ command_add_subcommand(parent, edit_object_command_new(obj));
+
+ return parent;
+}
+
+static void
+move_sash_command_destruct(Command_t *parent)
+{
+ MoveSashCommand_t *command = (MoveSashCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static void
+sash_move(GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+ MoveSashCommand_t *command = (MoveSashCommand_t*) data;
+ Object_t *obj = command->obj;
+ gint x, y, dx, dy;
+
+ x = get_real_coord((gint) event->x);
+ y = get_real_coord((gint) event->y);
+
+ if (x < 0)
+ x = 0;
+ if (x > command->image_width)
+ x = command->image_width;
+
+ if (y < 0)
+ y = 0;
+ if (y > command->image_height)
+ y = command->image_height;
+
+ dx = x - command->x;
+ dy = y - command->y;
+
+ command->x = x;
+ command->y = y;
+
+ command->sash_func(obj, dx, dy);
+ object_emit_geometry_signal(obj);
+
+ preview_redraw ();
+}
+
+static void
+sash_end(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ MoveSashCommand_t *command = (MoveSashCommand_t*) data;
+ Object_t *obj = command->obj;
+
+ g_signal_handlers_disconnect_by_func(widget,
+ sash_move, data);
+ g_signal_handlers_disconnect_by_func(widget,
+ sash_end, data);
+ if (obj->class->normalize)
+ object_normalize(obj);
+ preview_unset_tmp_obj(command->obj);
+ preview_redraw();
+ show_url();
+}
+
+static CmdExecuteValue_t
+move_sash_command_execute(Command_t *parent)
+{
+ MoveSashCommand_t *command = (MoveSashCommand_t*) parent;
+
+ hide_url();
+ g_signal_connect(command->widget, "button-release-event",
+ G_CALLBACK (sash_end), command);
+ g_signal_connect(command->widget, "motion-notify-event",
+ G_CALLBACK (sash_move), command);
+ preview_set_tmp_obj(command->obj);
+
+ return CMD_APPEND;
+}
+
+static void move_sash_command_redo(Command_t *command)
+{
+ /* do nothing, but avoid running execute again which will break event handling */
+}
diff --git a/plug-ins/imagemap/imap_cmd_move_selected.c b/plug-ins/imagemap/imap_cmd_move_selected.c
new file mode 100644
index 0000000..690a86a
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move_selected.c
@@ -0,0 +1,72 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t move_selected_command_execute(Command_t *parent);
+static void move_selected_command_undo(Command_t *parent);
+
+static CommandClass_t move_selected_command_class = {
+ NULL, /* move_selected_command_destruct */
+ move_selected_command_execute,
+ move_selected_command_undo,
+ NULL /* move_selected_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ gint dx;
+ gint dy;
+} MoveSelectedCommand_t;
+
+Command_t*
+move_selected_command_new(ObjectList_t *list, gint dx, gint dy)
+{
+ MoveSelectedCommand_t *command = g_new(MoveSelectedCommand_t, 1);
+ command->list = list;
+ command->dx = dx;
+ command->dy = dy;
+ return command_init(&command->parent, _("Move Selected Objects"),
+ &move_selected_command_class);
+}
+
+static CmdExecuteValue_t
+move_selected_command_execute(Command_t *parent)
+{
+ MoveSelectedCommand_t *command = (MoveSelectedCommand_t*) parent;
+ object_list_move_selected(command->list, command->dx, command->dy);
+ return CMD_APPEND;
+}
+
+static void
+move_selected_command_undo(Command_t *parent)
+{
+ MoveSelectedCommand_t *command = (MoveSelectedCommand_t*) parent;
+ object_list_move_selected(command->list, -command->dx, -command->dy);
+}
diff --git a/plug-ins/imagemap/imap_cmd_move_to_front.c b/plug-ins/imagemap/imap_cmd_move_to_front.c
new file mode 100644
index 0000000..c8f81e1
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move_to_front.c
@@ -0,0 +1,83 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t move_to_front_command_execute(Command_t *parent);
+
+static CommandClass_t move_to_front_command_class = {
+ NULL, /* move_to_front_command_destruct, */
+ move_to_front_command_execute,
+ NULL, /* move_to_front_command_undo */
+ NULL /* move_to_front_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} MoveToFrontCommand_t;
+
+Command_t*
+move_to_front_command_new(ObjectList_t *list)
+{
+ MoveToFrontCommand_t *command = g_new(MoveToFrontCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Move To Front"),
+ &move_to_front_command_class);
+}
+
+static void
+remove_one_object(Object_t *obj, gpointer data)
+{
+ MoveToFrontCommand_t *command = (MoveToFrontCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ delete_command_new(command->list, obj));
+}
+
+static void
+add_one_object(Object_t *obj, gpointer data)
+{
+ MoveToFrontCommand_t *command = (MoveToFrontCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ create_command_new(command->list, obj));
+}
+
+static CmdExecuteValue_t
+move_to_front_command_execute(Command_t *parent)
+{
+ MoveToFrontCommand_t *command = (MoveToFrontCommand_t*) parent;
+ gpointer id1, id2;
+
+ id1 = object_list_add_remove_cb(command->list, remove_one_object, command);
+ id2 = object_list_add_add_cb(command->list, add_one_object, command);
+
+ object_list_move_to_front(command->list);
+ object_list_remove_remove_cb(command->list, id1);
+ object_list_remove_add_cb(command->list, id2);
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_move_up.c b/plug-ins/imagemap/imap_cmd_move_up.c
new file mode 100644
index 0000000..ed253a2
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_move_up.c
@@ -0,0 +1,81 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t move_up_command_execute(Command_t *parent);
+
+static CommandClass_t move_up_command_class = {
+ NULL, /* move_up_command_destruct */
+ move_up_command_execute,
+ NULL, /* move_up_command_undo */
+ NULL /* move_up_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ gboolean add;
+} MoveUpCommand_t;
+
+Command_t*
+move_up_command_new(ObjectList_t *list)
+{
+ MoveUpCommand_t *command = g_new(MoveUpCommand_t, 1);
+ command->list = list;
+ command->add = FALSE;
+ return command_init(&command->parent, _("Move Up"), &move_up_command_class);
+}
+
+static void
+move_up_one_object(Object_t *obj, gpointer data)
+{
+ MoveUpCommand_t *command = (MoveUpCommand_t*) data;
+
+ if (command->add) {
+ command_add_subcommand(&command->parent,
+ object_up_command_new(command->list, obj));
+ command->add = FALSE;
+ }
+ else {
+ command->add = TRUE;
+ }
+}
+
+static CmdExecuteValue_t
+move_up_command_execute(Command_t *parent)
+{
+ MoveUpCommand_t *command = (MoveUpCommand_t*) parent;
+ gpointer id;
+
+ id = object_list_add_move_cb(command->list, move_up_one_object, command);
+ object_list_move_selected_up(command->list);
+ object_list_remove_move_cb(command->list, id);
+
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_object_down.c b/plug-ins/imagemap/imap_cmd_object_down.c
new file mode 100644
index 0000000..2849b71
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_object_down.c
@@ -0,0 +1,78 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void object_down_command_destruct(Command_t *parent);
+static CmdExecuteValue_t object_down_command_execute(Command_t *parent);
+static void object_down_command_undo(Command_t *parent);
+
+static CommandClass_t object_down_command_class = {
+ object_down_command_destruct,
+ object_down_command_execute,
+ object_down_command_undo,
+ NULL /* object_down_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ Object_t *obj;
+} ObjectDownCommand_t;
+
+Command_t*
+object_down_command_new(ObjectList_t *list, Object_t *obj)
+{
+ ObjectDownCommand_t *command = g_new(ObjectDownCommand_t, 1);
+ command->list = list;
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Move Down"),
+ &object_down_command_class);
+}
+
+static void
+object_down_command_destruct(Command_t *parent)
+{
+ ObjectDownCommand_t *command = (ObjectDownCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+object_down_command_execute(Command_t *parent)
+{
+ ObjectDownCommand_t *command = (ObjectDownCommand_t*) parent;
+ object_list_move_down(command->list, command->obj);
+ return CMD_APPEND;
+}
+
+static void
+object_down_command_undo(Command_t *parent)
+{
+ ObjectDownCommand_t *command = (ObjectDownCommand_t*) parent;
+ object_list_move_up(command->list, command->obj);
+}
diff --git a/plug-ins/imagemap/imap_cmd_object_move.c b/plug-ins/imagemap/imap_cmd_object_move.c
new file mode 100644
index 0000000..39c575c
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_object_move.c
@@ -0,0 +1,80 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void object_move_command_destruct(Command_t *parent);
+static CmdExecuteValue_t object_move_command_execute(Command_t *parent);
+static void object_move_command_undo(Command_t *parent);
+
+static CommandClass_t object_move_command_class = {
+ object_move_command_destruct,
+ object_move_command_execute,
+ object_move_command_undo,
+ NULL /* object_move_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Object_t *obj;
+ gint dx;
+ gint dy;
+} ObjectMoveCommand_t;
+
+Command_t*
+object_move_command_new(Object_t *obj, gint dx, gint dy)
+{
+ ObjectMoveCommand_t *command = g_new(ObjectMoveCommand_t, 1);
+ command->obj = object_ref(obj);
+ command->dx = dx;
+ command->dy = dy;
+ return command_init(&command->parent, _("Move"),
+ &object_move_command_class);
+}
+
+static void
+object_move_command_destruct(Command_t *parent)
+{
+ ObjectMoveCommand_t *command = (ObjectMoveCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+object_move_command_execute(Command_t *parent)
+{
+ ObjectMoveCommand_t *command = (ObjectMoveCommand_t*) parent;
+ object_move(command->obj, command->dx, command->dy);
+ return CMD_APPEND;
+}
+
+static void
+object_move_command_undo(Command_t *parent)
+{
+ ObjectMoveCommand_t *command = (ObjectMoveCommand_t*) parent;
+ object_move(command->obj, -command->dx, -command->dy);
+}
diff --git a/plug-ins/imagemap/imap_cmd_object_up.c b/plug-ins/imagemap/imap_cmd_object_up.c
new file mode 100644
index 0000000..edc8f40
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_object_up.c
@@ -0,0 +1,78 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void object_up_command_destruct(Command_t *parent);
+static CmdExecuteValue_t object_up_command_execute(Command_t *parent);
+static void object_up_command_undo(Command_t *parent);
+
+static CommandClass_t object_up_command_class = {
+ object_up_command_destruct,
+ object_up_command_execute,
+ object_up_command_undo,
+ NULL /* object_up_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ Object_t *obj;
+} ObjectUpCommand_t;
+
+Command_t*
+object_up_command_new(ObjectList_t *list, Object_t *obj)
+{
+ ObjectUpCommand_t *command = g_new(ObjectUpCommand_t, 1);
+ command->list = list;
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Move Up"),
+ &object_up_command_class);
+}
+
+static void
+object_up_command_destruct(Command_t *parent)
+{
+ ObjectUpCommand_t *command = (ObjectUpCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+object_up_command_execute(Command_t *parent)
+{
+ ObjectUpCommand_t *command = (ObjectUpCommand_t*) parent;
+ object_list_move_up(command->list, command->obj);
+ return CMD_APPEND;
+}
+
+static void
+object_up_command_undo(Command_t *parent)
+{
+ ObjectUpCommand_t *command = (ObjectUpCommand_t*) parent;
+ object_list_move_down(command->list, command->obj);
+}
diff --git a/plug-ins/imagemap/imap_cmd_paste.c b/plug-ins/imagemap/imap_cmd_paste.c
new file mode 100644
index 0000000..5855548
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_paste.c
@@ -0,0 +1,71 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t paste_command_execute(Command_t *parent);
+
+static CommandClass_t paste_command_class = {
+ NULL, /* paste_command_destruct, */
+ paste_command_execute,
+ NULL, /* paste_command_undo */
+ NULL /* paste_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} PasteCommand_t;
+
+Command_t*
+paste_command_new(ObjectList_t *list)
+{
+ PasteCommand_t *command = g_new(PasteCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Paste"), &paste_command_class);
+}
+
+static void
+paste_one_object(Object_t *obj, gpointer data)
+{
+ PasteCommand_t *command = (PasteCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ create_command_new(command->list, obj));
+}
+
+static CmdExecuteValue_t
+paste_command_execute(Command_t *parent)
+{
+ PasteCommand_t *command = (PasteCommand_t*) parent;
+ gpointer id;
+
+ id = object_list_add_add_cb(command->list, paste_one_object, command);
+ object_list_paste(command->list);
+ object_list_remove_add_cb(command->list, id);
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_select.c b/plug-ins/imagemap/imap_cmd_select.c
new file mode 100644
index 0000000..cbfa38d
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_select.c
@@ -0,0 +1,75 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void select_command_destruct(Command_t *parent);
+static CmdExecuteValue_t select_command_execute(Command_t *parent);
+static void select_command_undo(Command_t *parent);
+
+static CommandClass_t select_command_class = {
+ select_command_destruct,
+ select_command_execute,
+ select_command_undo,
+ NULL /* select_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Object_t *obj;
+} SelectCommand_t;
+
+Command_t*
+select_command_new(Object_t *obj)
+{
+ SelectCommand_t *command = g_new(SelectCommand_t, 1);
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Select"), &select_command_class);
+}
+
+static void
+select_command_destruct(Command_t *parent)
+{
+ SelectCommand_t *command = (SelectCommand_t*) parent;
+ object_unref(command->obj);
+}
+
+static CmdExecuteValue_t
+select_command_execute(Command_t *parent)
+{
+ SelectCommand_t *command = (SelectCommand_t*) parent;
+ object_select(command->obj);
+ return CMD_APPEND;
+}
+
+static void
+select_command_undo(Command_t *parent)
+{
+ SelectCommand_t *command = (SelectCommand_t*) parent;
+ object_unselect(command->obj);
+}
diff --git a/plug-ins/imagemap/imap_cmd_select_all.c b/plug-ins/imagemap/imap_cmd_select_all.c
new file mode 100644
index 0000000..286db3e
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_select_all.c
@@ -0,0 +1,74 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t select_all_command_execute(Command_t *parent);
+
+static CommandClass_t select_all_command_class = {
+ NULL, /* select_all_command_destruct, */
+ select_all_command_execute,
+ NULL, /* select_all_command_undo */
+ NULL /* select_all_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} SelectAllCommand_t;
+
+Command_t*
+select_all_command_new(ObjectList_t *list)
+{
+ SelectAllCommand_t *command = g_new(SelectAllCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Select All"),
+ &select_all_command_class);
+}
+
+static void
+select_one_object(Object_t *obj, gpointer data)
+{
+ SelectAllCommand_t *command = (SelectAllCommand_t*) data;
+ command_add_subcommand(&command->parent, select_command_new(obj));
+}
+
+static CmdExecuteValue_t
+select_all_command_execute(Command_t *parent)
+{
+ SelectAllCommand_t *command = (SelectAllCommand_t*) parent;
+ gpointer id;
+ CmdExecuteValue_t rvalue;
+
+ id = object_list_add_select_cb(command->list, select_one_object, command);
+ rvalue = (object_list_select_all(command->list))
+ ? CMD_APPEND : CMD_DESTRUCT;
+ object_list_remove_select_cb(command->list, id);
+
+ return rvalue;
+}
diff --git a/plug-ins/imagemap/imap_cmd_select_next.c b/plug-ins/imagemap/imap_cmd_select_next.c
new file mode 100644
index 0000000..325cacb
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_select_next.c
@@ -0,0 +1,76 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t select_next_command_execute(Command_t *parent);
+
+static CommandClass_t select_next_command_class = {
+ NULL, /* select_next_command_destruct */
+ select_next_command_execute,
+ NULL, /* select_next_command_undo */
+ NULL /* select_next_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} SelectNextCommand_t;
+
+Command_t*
+select_next_command_new(ObjectList_t *list)
+{
+ SelectNextCommand_t *command = g_new(SelectNextCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Select Next"),
+ &select_next_command_class);
+}
+
+static void
+select_one_object(Object_t *obj, gpointer data)
+{
+ SelectNextCommand_t *command = (SelectNextCommand_t*) data;
+ Command_t *sub_command;
+
+ sub_command = (obj->selected)
+ ? select_command_new(obj) : unselect_command_new(obj);
+ command_add_subcommand(&command->parent, sub_command);
+}
+
+static CmdExecuteValue_t
+select_next_command_execute(Command_t *parent)
+{
+ SelectNextCommand_t *command = (SelectNextCommand_t*) parent;
+ ObjectList_t *list = command->list;
+ gpointer id;
+
+ id = object_list_add_select_cb(list, select_one_object, command);
+ object_list_select_next(list);
+ object_list_remove_select_cb(list, id);
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_select_prev.c b/plug-ins/imagemap/imap_cmd_select_prev.c
new file mode 100644
index 0000000..9f5b8eb
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_select_prev.c
@@ -0,0 +1,76 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t select_prev_command_execute(Command_t *parent);
+
+static CommandClass_t select_prev_command_class = {
+ NULL, /* select_prev_command_destruct */
+ select_prev_command_execute,
+ NULL, /* select_prev_command_undo */
+ NULL /* select_prev_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} SelectPrevCommand_t;
+
+Command_t*
+select_prev_command_new(ObjectList_t *list)
+{
+ SelectPrevCommand_t *command = g_new(SelectPrevCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Select Previous"),
+ &select_prev_command_class);
+}
+
+static void
+select_one_object(Object_t *obj, gpointer data)
+{
+ SelectPrevCommand_t *command = (SelectPrevCommand_t*) data;
+ Command_t *sub_command;
+
+ sub_command = (obj->selected)
+ ? select_command_new(obj) : unselect_command_new(obj);
+ command_add_subcommand(&command->parent, sub_command);
+}
+
+static CmdExecuteValue_t
+select_prev_command_execute(Command_t *parent)
+{
+ SelectPrevCommand_t *command = (SelectPrevCommand_t*) parent;
+ ObjectList_t *list = command->list;
+ gpointer id;
+
+ id = object_list_add_select_cb(list, select_one_object, command);
+ object_list_select_prev(list);
+ object_list_remove_select_cb(list, id);
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_select_region.c b/plug-ins/imagemap/imap_cmd_select_region.c
new file mode 100644
index 0000000..6e0029b
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_select_region.c
@@ -0,0 +1,142 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_rectangle.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t select_region_command_execute(Command_t *parent);
+
+static CommandClass_t select_region_command_class = {
+ NULL, /* select_region_command_destruct, */
+ select_region_command_execute,
+ NULL, /* select_region_command_undo */
+ NULL /* select_region_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ GtkWidget *widget;
+ ObjectList_t *list;
+ gint x;
+ gint y;
+ Object_t *obj;
+ Command_t *unselect_command;
+} SelectRegionCommand_t;
+
+Command_t*
+select_region_command_new(GtkWidget *widget, ObjectList_t *list, gint x,
+ gint y)
+{
+ SelectRegionCommand_t *command = g_new(SelectRegionCommand_t, 1);
+ Command_t *sub_command;
+
+ command->widget = widget;
+ command->list = list;
+ command->x = x;
+ command->y = y;
+ (void) command_init(&command->parent, _("Select Region"),
+ &select_region_command_class);
+
+ sub_command = unselect_all_command_new(list, NULL);
+ command_add_subcommand(&command->parent, sub_command);
+ command->unselect_command = sub_command;
+
+ return &command->parent;
+}
+
+static void
+select_one_object(Object_t *obj, gpointer data)
+{
+ SelectRegionCommand_t *command = (SelectRegionCommand_t*) data;
+ command_add_subcommand(&command->parent, select_command_new(obj));
+}
+
+static void
+select_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+ SelectRegionCommand_t *command = (SelectRegionCommand_t*) data;
+ Object_t *obj = command->obj;
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+
+ gint x = get_real_coord((gint) event->x);
+ gint y = get_real_coord((gint) event->y);
+
+ rectangle->width = x - rectangle->x;
+ rectangle->height = y - rectangle->y;
+
+ preview_redraw ();
+}
+
+static void
+select_release(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ SelectRegionCommand_t *command = (SelectRegionCommand_t*) data;
+ Object_t *obj = command->obj;
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ gpointer id;
+ gint count;
+
+ g_signal_handlers_disconnect_by_func(widget,
+ select_motion, data);
+ g_signal_handlers_disconnect_by_func(widget,
+ select_release, data);
+
+ object_normalize(obj);
+
+ id = object_list_add_select_cb(command->list, select_one_object, command);
+ count = object_list_select_region(command->list, rectangle->x, rectangle->y,
+ rectangle->width, rectangle->height);
+ object_list_remove_select_cb(command->list, id);
+
+ if (count) {
+ command_list_add(&command->parent);
+ } else { /* Nothing selected */
+ if (command->unselect_command->sub_commands)
+ command_list_add(&command->parent);
+ }
+ preview_unset_tmp_obj (command->obj);
+
+ preview_redraw ();
+}
+
+static CmdExecuteValue_t
+select_region_command_execute(Command_t *parent)
+{
+ SelectRegionCommand_t *command = (SelectRegionCommand_t*) parent;
+
+ command->obj = create_rectangle(command->x, command->y, 0, 0);
+ preview_set_tmp_obj (command->obj);
+
+ g_signal_connect(command->widget, "button-release-event",
+ G_CALLBACK (select_release), command);
+ g_signal_connect(command->widget, "motion-notify-event",
+ G_CALLBACK (select_motion), command);
+
+ return CMD_IGNORE;
+}
diff --git a/plug-ins/imagemap/imap_cmd_send_to_back.c b/plug-ins/imagemap/imap_cmd_send_to_back.c
new file mode 100644
index 0000000..99e2e1e
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_send_to_back.c
@@ -0,0 +1,83 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static CmdExecuteValue_t send_to_back_command_execute(Command_t *parent);
+
+static CommandClass_t send_to_back_command_class = {
+ NULL, /* send_to_back_command_destruct, */
+ send_to_back_command_execute,
+ NULL, /* send_to_back_command_undo */
+ NULL /* send_to_back_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+} SendToBackCommand_t;
+
+Command_t*
+send_to_back_command_new(ObjectList_t *list)
+{
+ SendToBackCommand_t *command = g_new(SendToBackCommand_t, 1);
+ command->list = list;
+ return command_init(&command->parent, _("Send To Back"),
+ &send_to_back_command_class);
+}
+
+static void
+remove_one_object(Object_t *obj, gpointer data)
+{
+ SendToBackCommand_t *command = (SendToBackCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ delete_command_new(command->list, obj));
+}
+
+static void
+add_one_object(Object_t *obj, gpointer data)
+{
+ SendToBackCommand_t *command = (SendToBackCommand_t*) data;
+ command_add_subcommand(&command->parent,
+ create_command_new(command->list, obj));
+}
+
+static CmdExecuteValue_t
+send_to_back_command_execute(Command_t *parent)
+{
+ SendToBackCommand_t *command = (SendToBackCommand_t*) parent;
+ gpointer id1, id2;
+
+ id1 = object_list_add_remove_cb(command->list, remove_one_object, command);
+ id2 = object_list_add_add_cb(command->list, add_one_object, command);
+
+ object_list_send_to_back(command->list);
+ object_list_remove_remove_cb(command->list, id1);
+ object_list_remove_add_cb(command->list, id2);
+ return CMD_APPEND;
+}
diff --git a/plug-ins/imagemap/imap_cmd_unselect.c b/plug-ins/imagemap/imap_cmd_unselect.c
new file mode 100644
index 0000000..23bac7c
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_unselect.c
@@ -0,0 +1,76 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void unselect_command_destruct(Command_t *parent);
+static CmdExecuteValue_t unselect_command_execute(Command_t *parent);
+static void unselect_command_undo(Command_t *parent);
+
+static CommandClass_t unselect_command_class = {
+ unselect_command_destruct,
+ unselect_command_execute,
+ unselect_command_undo,
+ NULL /* unselect_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ Object_t *obj;
+} UnselectCommand_t;
+
+Command_t*
+unselect_command_new(Object_t *obj)
+{
+ UnselectCommand_t *command = g_new(UnselectCommand_t, 1);
+ command->obj = object_ref(obj);
+ return command_init(&command->parent, _("Unselect"),
+ &unselect_command_class);
+}
+
+static void
+unselect_command_destruct(Command_t *command)
+{
+ UnselectCommand_t *unselect_command = (UnselectCommand_t*) command;
+ object_unref(unselect_command->obj);
+}
+
+static CmdExecuteValue_t
+unselect_command_execute(Command_t *command)
+{
+ UnselectCommand_t *unselect_command = (UnselectCommand_t*) command;
+ object_unselect(unselect_command->obj);
+ return CMD_APPEND;
+}
+
+static void
+unselect_command_undo(Command_t *command)
+{
+ UnselectCommand_t *unselect_command = (UnselectCommand_t*) command;
+ object_select(unselect_command->obj);
+}
diff --git a/plug-ins/imagemap/imap_cmd_unselect_all.c b/plug-ins/imagemap/imap_cmd_unselect_all.c
new file mode 100644
index 0000000..f1e45e4
--- /dev/null
+++ b/plug-ins/imagemap/imap_cmd_unselect_all.c
@@ -0,0 +1,90 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void unselect_all_command_destruct(Command_t *command);
+static CmdExecuteValue_t unselect_all_command_execute(Command_t *command);
+
+/* COMMAND_PROTO(unselect_all_command); */
+
+static CommandClass_t unselect_all_command_class = {
+ unselect_all_command_destruct,
+ unselect_all_command_execute,
+ NULL, /* unselect_all_command_undo */
+ NULL /* unselect_all_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ ObjectList_t *list;
+ Object_t *exception;
+} UnselectAllCommand_t;
+
+Command_t*
+unselect_all_command_new(ObjectList_t *list, Object_t *exception)
+{
+ UnselectAllCommand_t *command = g_new(UnselectAllCommand_t, 1);
+ command->list = list;
+ command->exception = (exception) ? object_ref(exception) : exception;
+ return command_init(&command->parent, _("Unselect All"),
+ &unselect_all_command_class);
+}
+
+static void
+unselect_all_command_destruct(Command_t *parent)
+{
+ UnselectAllCommand_t *command = (UnselectAllCommand_t*) parent;
+ if (command->exception)
+ object_unref(command->exception);
+}
+
+static void
+select_one_object(Object_t *obj, gpointer data)
+{
+ UnselectAllCommand_t *command = (UnselectAllCommand_t*) data;
+ command_add_subcommand(&command->parent, unselect_command_new(obj));
+}
+
+static CmdExecuteValue_t
+unselect_all_command_execute(Command_t *parent)
+{
+ UnselectAllCommand_t *command = (UnselectAllCommand_t*) parent;
+ gpointer id;
+ CmdExecuteValue_t rvalue;
+
+ id = object_list_add_select_cb(command->list, select_one_object,
+ command);
+ if (object_list_deselect_all(command->list, command->exception)) {
+ rvalue = CMD_APPEND;
+ } else {
+ rvalue = CMD_DESTRUCT;
+ }
+ object_list_remove_select_cb(command->list, id);
+ return rvalue;
+}
diff --git a/plug-ins/imagemap/imap_command.c b/plug-ins/imagemap/imap_command.c
new file mode 100644
index 0000000..ae81c1f
--- /dev/null
+++ b/plug-ins/imagemap/imap_command.c
@@ -0,0 +1,384 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_command.h"
+
+#define INFINITE_UNDO_LEVELS -1
+
+static void command_destruct(Command_t *command);
+
+static CommandList_t _command_list = {NULL, DEFAULT_UNDO_LEVELS};
+static CommandList_t *_current_command_list = &_command_list;
+
+static void
+command_list_callback_add(CommandListCallback_t *list,
+ CommandListCallbackFunc_t func, gpointer data)
+{
+ CommandListCB_t *cb = g_new(CommandListCB_t, 1);
+ cb->func = func;
+ cb->data = data;
+ list->list = g_list_append(list->list, cb);
+}
+
+static void
+command_list_callback_call(CommandListCallback_t *list, Command_t *command)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ CommandListCB_t *cb = (CommandListCB_t*) p->data;
+ cb->func(command, cb->data);
+ }
+}
+
+CommandList_t*
+command_list_new(gint undo_levels)
+{
+ CommandList_t *list = g_new(CommandList_t, 1);
+ list->parent = NULL;
+ list->undo_levels = undo_levels;
+ list->list = NULL;
+ list->undo = NULL;
+ list->redo = NULL;
+ list->update_cb.list = NULL;
+ return list;
+}
+
+static void
+command_list_clear(CommandList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next)
+ command_destruct((Command_t*) p->data);
+ g_list_free(list->list);
+ list->list = NULL;
+ list->undo = NULL;
+ list->redo = NULL;
+ command_list_callback_call(&list->update_cb, NULL);
+}
+
+void
+command_list_destruct(CommandList_t *list)
+{
+ command_list_clear(list);
+ g_free(list);
+}
+
+void
+command_list_remove_all(void)
+{
+ command_list_clear(&_command_list);
+}
+
+static void
+_command_list_add(CommandList_t *list, Command_t *command)
+{
+ GList *p, *q;
+
+ /* Remove rest */
+ for (p = list->redo; p; p = q) {
+ Command_t *curr = (Command_t*) p->data;
+ q = p->next;
+ command_destruct(curr);
+ list->list = g_list_remove_link(list->list, p);
+ }
+ if (g_list_length(list->list) == list->undo_levels) {
+ GList *first = g_list_first(list->list);
+ Command_t *curr = (Command_t*) first->data;
+ command_destruct(curr);
+ list->list = g_list_remove_link(list->list, first);
+ }
+ list->list = g_list_append(list->list, (gpointer) command);
+ list->undo = g_list_last(list->list);
+ list->redo = NULL;
+
+ command_list_callback_call(&list->update_cb, command);
+}
+
+void
+command_list_add(Command_t *command)
+{
+ _command_list_add(_current_command_list, command);
+}
+
+/* Fix me! */
+void
+subcommand_list_add(CommandList_t *list, Command_t *command)
+{
+ _command_list_add(list, command);
+}
+
+static CommandClass_t parent_command_class = {
+ NULL, /* parent_command_destruct */
+ NULL, /* parent_command_execute */
+ NULL, /* parent_command_undo */
+ NULL /* parent_command_redo */
+};
+
+static Command_t*
+command_list_start(CommandList_t *list, const gchar *name)
+{
+ Command_t *command = g_new(Command_t, 1);
+ command_init(command, name, &parent_command_class);
+ command->sub_commands = command_list_new(INFINITE_UNDO_LEVELS);
+
+ command_list_add(command);
+ command->sub_commands->parent = _current_command_list;
+ _current_command_list = command->sub_commands;
+
+ return command;
+}
+
+static void
+command_list_end(CommandList_t *list)
+{
+ _current_command_list = list->parent;
+}
+
+Command_t*
+subcommand_start(const gchar *name)
+{
+ return command_list_start(_current_command_list, name);
+}
+
+void
+subcommand_end(void)
+{
+ command_list_end(_current_command_list);
+}
+
+static void
+_command_list_set_undo_level(CommandList_t *list, gint level)
+{
+ gint diff = g_list_length(list->list) - level;
+ if (diff > 0) {
+ GList *p, *q;
+ /* first remove data at the front */
+ for (p = list->list; diff && p != list->undo; p = q, diff--) {
+ Command_t *curr = (Command_t*) p->data;
+ q = p->next;
+ command_destruct(curr);
+ list->list = g_list_remove_link(list->list, p);
+ }
+
+ /* If still to long start removing redo levels at the end */
+ for (p = g_list_last(list->list); diff && p != list->undo; p = q,
+ diff--) {
+ Command_t *curr = (Command_t*) p->data;
+ q = p->prev;
+ command_destruct(curr);
+ list->list = g_list_remove_link(list->list, p);
+ }
+ command_list_callback_call(&list->update_cb,
+ (Command_t*) list->undo->data);
+ }
+ list->undo_levels = level;
+}
+
+void
+command_list_set_undo_level(gint level)
+{
+ _command_list_set_undo_level(&_command_list, level);
+}
+
+Command_t*
+command_list_get_redo_command(void)
+{
+ return (_command_list.redo) ? (Command_t*) _command_list.redo->data : NULL;
+}
+
+void
+command_list_add_update_cb(CommandListCallbackFunc_t func, gpointer data)
+{
+ command_list_callback_add(&_command_list.update_cb, func, data);
+}
+
+static void
+command_destruct(Command_t *command)
+{
+ if (command->sub_commands)
+ command_list_destruct(command->sub_commands);
+ if (command->class->destruct)
+ command->class->destruct(command);
+}
+
+static void
+command_list_execute(CommandList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Command_t *command = (Command_t*) p->data;
+ if (command->sub_commands)
+ command_list_execute(command->sub_commands);
+ if (command->class->execute)
+ (void) command->class->execute(command);
+ }
+}
+
+void
+command_execute(Command_t *command)
+{
+ if (command->locked) {
+ command->locked = FALSE;
+ } else {
+ if (command->sub_commands)
+ command_list_execute(command->sub_commands);
+ if (command->class->execute) {
+ CmdExecuteValue_t value = command->class->execute(command);
+ if (value == CMD_APPEND)
+ command_list_add(command);
+ else if (value == CMD_DESTRUCT)
+ command_destruct(command);
+ }
+ }
+}
+
+void
+command_redo(Command_t *command)
+{
+ if (command->sub_commands)
+ command_list_redo_all(command->sub_commands);
+ if (command->class->redo)
+ command->class->redo(command);
+ else if (command->class->execute)
+ (void) command->class->execute(command);
+}
+
+void
+command_undo(Command_t *command)
+{
+ if (command->sub_commands)
+ command_list_undo_all(command->sub_commands);
+ if (command->class->undo)
+ command->class->undo(command);
+}
+
+void
+command_set_name(Command_t *command, const gchar *name)
+{
+ command->name = name;
+ command_list_callback_call(&_command_list.update_cb, command);
+}
+
+void
+command_list_undo(CommandList_t *list)
+{
+ Command_t *command = (Command_t*) list->undo->data;
+ command_undo(command);
+
+ list->redo = list->undo;
+ list->undo = list->undo->prev;
+ if (list->undo)
+ command = (Command_t*) list->undo->data;
+ else
+ command = NULL;
+ command_list_callback_call(&list->update_cb, command);
+}
+
+void
+command_list_undo_all(CommandList_t *list)
+{
+ while (list->undo)
+ command_list_undo(list);
+}
+
+void
+last_command_undo(void)
+{
+ command_list_undo(&_command_list);
+}
+
+void
+command_list_redo(CommandList_t *list)
+{
+ Command_t *command = (Command_t*) list->redo->data;
+ command_redo(command);
+
+ list->undo = list->redo;
+ list->redo = list->redo->next;
+ command_list_callback_call(&list->update_cb, command);
+}
+
+void
+command_list_redo_all(CommandList_t *list)
+{
+ while (list->redo)
+ command_list_redo(list);
+}
+
+void
+last_command_redo(void)
+{
+ command_list_redo(&_command_list);
+}
+
+Command_t*
+command_init(Command_t *command, const gchar *name, CommandClass_t *class)
+{
+ command->sub_commands = NULL;
+ command->name = name;
+ command->class = class;
+ command->locked = FALSE;
+ return command;
+}
+
+void
+command_add_subcommand(Command_t *command, Command_t *sub_command)
+{
+ if (!command->sub_commands)
+ command->sub_commands = command_list_new(INFINITE_UNDO_LEVELS);
+ subcommand_list_add(command->sub_commands, sub_command);
+}
+
+static CmdExecuteValue_t basic_command_execute(Command_t *command);
+
+static CommandClass_t basic_command_class = {
+ NULL, /* basic_command_destruct */
+ basic_command_execute,
+ NULL,
+ NULL /* basic_command_redo */
+};
+
+typedef struct {
+ Command_t parent;
+ void (*func)(void);
+} BasicCommand_t;
+
+Command_t*
+command_new(void (*func)(void))
+{
+ BasicCommand_t *command = g_new(BasicCommand_t, 1);
+ command->func = func;
+ return command_init(&command->parent, "Unknown", &basic_command_class);
+}
+
+static CmdExecuteValue_t
+basic_command_execute(Command_t *command)
+{
+ ((BasicCommand_t*) command)->func();
+ return CMD_DESTRUCT;
+}
diff --git a/plug-ins/imagemap/imap_command.h b/plug-ins/imagemap/imap_command.h
new file mode 100644
index 0000000..1676d2d
--- /dev/null
+++ b/plug-ins/imagemap/imap_command.h
@@ -0,0 +1,103 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_COMMAND_H
+#define _IMAP_COMMAND_H
+
+#include "imap_object.h"
+
+#define DEFAULT_UNDO_LEVELS 10
+
+typedef struct CommandClass_t CommandClass_t;
+typedef struct Command_t Command_t;
+typedef struct CommandList_t CommandList_t;
+
+typedef enum {CMD_APPEND, CMD_DESTRUCT, CMD_IGNORE} CmdExecuteValue_t;
+
+struct CommandClass_t {
+ void (*destruct)(Command_t*);
+ CmdExecuteValue_t (*execute)(Command_t*);
+ void (*undo)(Command_t*);
+ void (*redo)(Command_t*);
+};
+
+struct Command_t {
+ CommandClass_t *class;
+ CommandList_t *sub_commands;
+ const gchar *name;
+ gboolean locked;
+};
+
+
+typedef Command_t* (*CommandFactory_t)(void);
+
+typedef void (*CommandListCallbackFunc_t)(Command_t*, gpointer);
+
+typedef struct {
+ CommandListCallbackFunc_t func;
+ gpointer data;
+} CommandListCB_t;
+
+typedef struct {
+ GList *list;
+} CommandListCallback_t;
+
+struct CommandList_t {
+ CommandList_t *parent;
+ gint undo_levels;
+ GList *list;
+ GList *undo; /* Pointer to current undo command */
+ GList *redo; /* Pointer to current redo command */
+ CommandListCallback_t update_cb;
+};
+
+CommandList_t *command_list_new(gint undo_levels);
+void command_list_destruct(CommandList_t *list);
+void command_list_set_undo_level(gint level);
+void command_list_add(Command_t *command);
+void command_list_remove_all(void);
+void command_list_undo(CommandList_t *list);
+void command_list_undo_all(CommandList_t *list);
+void command_list_redo(CommandList_t *list);
+void command_list_redo_all(CommandList_t *list);
+void command_list_add_update_cb(CommandListCallbackFunc_t func, gpointer data);
+Command_t *command_list_get_redo_command(void);
+
+Command_t *command_new(void (*func)(void));
+Command_t *command_init(Command_t *command, const gchar *name,
+ CommandClass_t *class);
+void command_execute(Command_t *command);
+void command_undo(Command_t *command);
+void command_redo(Command_t *command);
+void command_set_name(Command_t *command, const gchar *name);
+void command_add_subcommand(Command_t *command, Command_t *sub_command);
+
+void last_command_undo(void);
+void last_command_redo(void);
+
+void subcommand_list_add(CommandList_t *list, Command_t *command);
+Command_t *subcommand_start(const gchar *name);
+void subcommand_end(void);
+
+#define command_lock(command) ((command)->locked = TRUE)
+
+#endif /* _IMAP_COMMAND_H */
diff --git a/plug-ins/imagemap/imap_commands.h b/plug-ins/imagemap/imap_commands.h
new file mode 100644
index 0000000..af8637b
--- /dev/null
+++ b/plug-ins/imagemap/imap_commands.h
@@ -0,0 +1,64 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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.i
+ *
+ * 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 _IMAP_COMMANDS_H
+#define _IMAP_COMMANDS_H
+
+#include "imap_command.h"
+#include "imap_object.h"
+#include "imap_preview.h"
+
+Command_t *clear_command_new(ObjectList_t *list);
+Command_t *copy_command_new(ObjectList_t *list);
+Command_t *copy_object_command_new(Object_t *obj);
+Command_t *create_command_new(ObjectList_t *list, Object_t *obj);
+Command_t *cut_command_new(ObjectList_t *list);
+Command_t *cut_object_command_new(Object_t *obj);
+Command_t *delete_command_new(ObjectList_t *list, Object_t *obj);
+Command_t *delete_point_command_new(Object_t *obj, GdkPoint *point);
+Command_t *edit_object_command_new(Object_t *obj);
+Command_t *gimp_guides_command_new(ObjectList_t *list,
+ gint32 _drawable_id);
+Command_t *guides_command_new(ObjectList_t *list);
+Command_t *insert_point_command_new(Object_t *obj, gint x, gint y, gint edge);
+Command_t *move_down_command_new(ObjectList_t *list);
+Command_t *move_command_new(Preview_t *preview, Object_t *obj, gint x, gint y);
+Command_t *move_sash_command_new(GtkWidget *widget, Object_t *obj,
+ gint x, gint y, MoveSashFunc_t sash_func);
+Command_t *move_selected_command_new(ObjectList_t *list, gint dx, gint dy);
+Command_t *move_to_front_command_new(ObjectList_t *list);
+Command_t *move_up_command_new(ObjectList_t *list);
+Command_t *object_down_command_new(ObjectList_t *list, Object_t *obj);
+Command_t *object_move_command_new(Object_t *obj, gint x, gint y);
+Command_t *object_up_command_new(ObjectList_t *list, Object_t *obj);
+Command_t *paste_command_new(ObjectList_t *list);
+Command_t *select_all_command_new(ObjectList_t *list);
+Command_t *select_command_new(Object_t *obj);
+Command_t *select_next_command_new(ObjectList_t *list);
+Command_t *select_prev_command_new(ObjectList_t *list);
+Command_t *select_region_command_new(GtkWidget *widget, ObjectList_t *list,
+ gint x, gint y);
+Command_t *send_to_back_command_new(ObjectList_t *list);
+Command_t *unselect_all_command_new(ObjectList_t *list, Object_t *exception);
+Command_t *unselect_command_new(Object_t *obj);
+
+#endif /* _IMAP_COMMANDS_H */
diff --git a/plug-ins/imagemap/imap_csim.l b/plug-ins/imagemap/imap_csim.l
new file mode 100644
index 0000000..32b9803
--- /dev/null
+++ b/plug-ins/imagemap/imap_csim.l
@@ -0,0 +1,137 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2000 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_csim_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+%}
+
+%option noyywrap
+%option noinput
+%option nounput
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_\-]*
+WS [ \t\n]+
+
+%x quoted_string
+%x comment
+
+%%
+
+\<!--\ #$AUTHOR: {
+ BEGIN(comment);
+ return AUTHOR;
+ }
+
+\<!--\ #$DESCRIPTION: {
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+
+\<!-- {
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+
+<comment>--\> {
+ BEGIN(INITIAL);
+ return END_COMMENT;
+ }
+
+<comment>.*/--\> {
+ csim_lval.id = g_strndup (yytext, yyleng);
+ return STRING;
+ }
+
+IMG return IMG;
+
+SRC return SRC;
+
+WIDTH return WIDTH;
+
+HEIGHT return HEIGHT;
+
+BORDER return BORDER;
+
+USEMAP return USEMAP;
+
+MAP return START_MAP;
+
+\/MAP return END_MAP;
+
+NAME return NAME;
+
+AREA return AREA;
+
+SHAPE return SHAPE;
+
+COORDS return COORDS;
+
+TARGET return TARGET;
+
+ONMOUSEOVER return ONMOUSEOVER;
+
+ONMOUSEOUT return ONMOUSEOUT;
+
+ONFOCUS return ONFOCUS;
+
+ONBLUR return ONBLUR;
+
+ALT return ALT;
+
+HREF return HREF;
+
+NOHREF return NOHREF;
+
+\" {
+ BEGIN(quoted_string);
+ }
+
+<quoted_string>\" {
+ BEGIN(INITIAL);
+ return STRING;
+ }
+
+<quoted_string>[^\"]* {
+ csim_lval.id = g_strndup (yytext, yyleng);
+ }
+
+-?{DIGIT}*"."?{DIGIT}*([Ee][-+]?{DIGIT}*)? {
+ csim_lval.value = g_ascii_strtod (yytext, NULL);
+ return FLOAT;
+ }
+
+{WS} ; /* Eat white space */
+
+. return *yytext;
+
+%%
+
diff --git a/plug-ins/imagemap/imap_csim.y b/plug-ins/imagemap/imap_csim.y
new file mode 100644
index 0000000..abc2dff
--- /dev/null
+++ b/plug-ins/imagemap/imap_csim.y
@@ -0,0 +1,396 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int csim_lex(void);
+extern int csim_restart(FILE *csim_in);
+static void csim_error(char* s);
+static gchar * unescape_text(gchar *input);
+
+static enum {UNDEFINED, RECTANGLE, CIRCLE, POLYGON} current_type;
+static Object_t *current_object;
+static MapInfo_t *_map_info;
+
+%}
+
+%union {
+ int val;
+ double value;
+ char *id;
+}
+
+%token<val> IMG SRC WIDTH HEIGHT BORDER USEMAP
+%token<val> START_MAP END_MAP NAME AREA SHAPE COORDS ALT HREF NOHREF
+%token<val> TARGET ONMOUSEOVER ONMOUSEOUT ONFOCUS ONBLUR
+%token<val> AUTHOR DESCRIPTION BEGIN_COMMENT END_COMMENT
+%token<value> FLOAT
+%token<id> STRING
+
+%type<val> integer_value
+
+%%
+
+csim_file : image start_map comment_lines area_list end_map
+ ;
+
+image : '<' IMG SRC '=' STRING image_tags xhtml_close
+ {
+ g_strreplace(&_map_info->image_name, $5);
+ g_free ($5);
+ }
+ ;
+
+image_tags : /* Empty */
+ | image_tags image_tag
+ ;
+
+image_tag : image_width
+ | image_height
+ | BORDER '=' integer_value {}
+ | USEMAP '=' STRING { g_free ($3); }
+ | ALT '=' STRING { g_free ($3); }
+ ;
+
+image_width : WIDTH '=' integer_value
+ {
+ _map_info->old_image_width = $3;
+ }
+ ;
+
+image_height : HEIGHT '=' integer_value
+ {
+ _map_info->old_image_height = $3;
+ }
+ ;
+
+integer_value : FLOAT
+ {
+ $$ = (gint) $1;
+ }
+ | STRING
+ {
+ $$ = (gint) g_ascii_strtod ($1, NULL);
+ g_free ($1);
+ }
+ ;
+
+start_map : '<' START_MAP NAME '=' STRING '>'
+ {
+ g_strreplace(&_map_info->title, $5);
+ g_free ($5);
+ }
+ ;
+
+comment_lines : /* empty */
+ | comment_lines comment_line
+ ;
+
+comment_line : author_line
+ | description_line
+ | real_comment
+ ;
+
+real_comment : BEGIN_COMMENT STRING END_COMMENT
+ {
+ g_free ($2);
+ }
+ ;
+
+author_line : AUTHOR STRING END_COMMENT
+ {
+ g_strreplace(&_map_info->author, $2);
+ g_free ($2);
+ }
+ ;
+
+description_line: DESCRIPTION STRING END_COMMENT
+ {
+ gchar *description;
+
+ description = g_strconcat(_map_info->description, $2, "\n",
+ NULL);
+ g_strreplace(&_map_info->description, description);
+ g_free ($2);
+ }
+ ;
+
+area_list : /* empty */
+ | area_list area
+ ;
+
+area : '<' AREA tag_list xhtml_close
+ {
+ if (current_type != UNDEFINED)
+ add_shape(current_object);
+ }
+ ;
+
+xhtml_close : '>'
+ | '/' '>'
+ ;
+
+tag_list : /* Empty */
+ | tag_list tag
+ ;
+
+tag : shape_tag
+ | coords_tag
+ | href_tag
+ | nohref_tag
+ | alt_tag
+ | target_tag
+ | onmouseover_tag
+ | onmouseout_tag
+ | onfocus_tag
+ | onblur_tag
+ ;
+
+shape_tag : SHAPE '=' STRING
+ {
+ if (!g_ascii_strcasecmp($3, "RECT")) {
+ current_object = create_rectangle(0, 0, 0, 0);
+ current_type = RECTANGLE;
+ } else if (!g_ascii_strcasecmp($3, "CIRCLE")) {
+ current_object = create_circle(0, 0, 0);
+ current_type = CIRCLE;
+ } else if (!g_ascii_strcasecmp($3, "POLY")) {
+ current_object = create_polygon(NULL);
+ current_type = POLYGON;
+ } else if (!g_ascii_strcasecmp($3, "DEFAULT")) {
+ current_type = UNDEFINED;
+ }
+ g_free ($3);
+ }
+ ;
+
+coords_tag : COORDS '=' STRING
+ {
+ char *p;
+ if (current_type == RECTANGLE) {
+ Rectangle_t *rectangle;
+
+ rectangle = ObjectToRectangle(current_object);
+ p = strtok($3, ",");
+ rectangle->x = atoi(p);
+ p = strtok(NULL, ",");
+ rectangle->y = atoi(p);
+ p = strtok(NULL, ",");
+ rectangle->width = atoi(p) - rectangle->x;
+ p = strtok(NULL, ",");
+ rectangle->height = atoi(p) - rectangle->y;
+ } else if (current_type == CIRCLE) {
+ Circle_t *circle;
+
+ circle = ObjectToCircle(current_object);
+ p = strtok($3, ",");
+ circle->x = atoi(p);
+ p = strtok(NULL, ",");
+ circle->y = atoi(p);
+ p = strtok(NULL, ",");
+ circle->r = atoi(p);
+ } else if (current_type == POLYGON) {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GList *points;
+ GdkPoint *point, *first;
+ gint x, y;
+
+ p = strtok($3, ",");
+ x = atoi(p);
+ p = strtok(NULL, ",");
+ y = atoi(p);
+ point = new_point(x, y);
+ points = g_list_append(NULL, (gpointer) point);
+
+ while(1) {
+ p = strtok(NULL, ",");
+ if (!p)
+ break;
+ x = atoi(p);
+ p = strtok(NULL, ",");
+ y = atoi(p);
+ point = new_point(x, y);
+ points = g_list_append(points, (gpointer) point);
+ }
+ /* Remove last point if duplicate */
+ first = (GdkPoint*) points->data;
+ polygon->points = points;
+ if (first->x == point->x && first->y == point->y)
+ polygon_remove_last_point(polygon);
+ polygon->points = points;
+ }
+
+ g_free ($3);
+ }
+ ;
+
+href_tag : HREF '=' STRING
+ {
+ if (current_type == UNDEFINED) {
+ g_strreplace(&_map_info->default_url, $3);
+ } else {
+ object_set_url(current_object, unescape_text($3));
+ }
+ g_free ($3);
+ }
+ ;
+
+nohref_tag : NOHREF optional_value
+ {
+ }
+ ;
+
+optional_value : /* Empty */
+ | '=' STRING
+ {
+ g_free ($2);
+ }
+ ;
+
+alt_tag : ALT '=' STRING
+ {
+ object_set_comment(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+target_tag : TARGET '=' STRING
+ {
+ object_set_target(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+onmouseover_tag : ONMOUSEOVER '=' STRING
+ {
+ object_set_mouse_over(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+onmouseout_tag : ONMOUSEOUT '=' STRING
+ {
+ object_set_mouse_out(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+onfocus_tag : ONFOCUS '=' STRING
+ {
+ object_set_focus(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+onblur_tag : ONBLUR '=' STRING
+ {
+ object_set_blur(current_object, unescape_text($3));
+ g_free ($3);
+ }
+ ;
+
+end_map : '<' END_MAP '>'
+ ;
+
+%%
+
+static void
+csim_error(char* s)
+{
+ extern FILE *csim_in;
+ csim_restart(csim_in);
+}
+
+gboolean
+load_csim (const char* filename)
+{
+ gboolean status;
+ extern FILE *csim_in;
+ csim_in = g_fopen(filename, "r");
+ if (csim_in) {
+ _map_info = get_map_info();
+ status = !csim_parse();
+ fclose(csim_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
+
+static gchar*
+unescape_text (gchar *input)
+{
+ /*
+ * We "unescape" simple things "in place", knowing that unescaped
+ * strings always are shorter than the original input.
+ *
+ * It is a shame there is no g_markup_unescape_text() function, but
+ * instead you have to create a full GMarkupParser/Context.
+ */
+ struct token {
+ const char *escaped;
+ const char unescaped;
+ };
+ const struct token tab[] = {
+ { "&quot;", '"' },
+ { "&apos;", '\'' },
+ { "&amp;", '&' },
+ { "&lt;", '<' },
+ { "&gt;", '>' }
+ };
+
+ size_t i;
+ for (i = 0; i < (sizeof tab / sizeof tab[0]); i++)
+ {
+ const size_t escaped_len = strlen (tab[i].escaped);
+ char *p;
+
+ /* FIXME: The following code does not perform a UTF-8 substring
+ search. */
+ for (p = strstr (input, tab[i].escaped);
+ p != NULL;
+ p = strstr (p, tab[i].escaped))
+ {
+ size_t copy_len;
+ *p++ = tab[i].unescaped;
+ copy_len = strlen (p) - escaped_len + 2;
+ memmove (p, p + escaped_len - 1, copy_len);
+ if (*p == 0)
+ break;
+ }
+ }
+
+ return input;
+}
diff --git a/plug-ins/imagemap/imap_csim_lex.c b/plug-ins/imagemap/imap_csim_lex.c
new file mode 100644
index 0000000..88c8b86
--- /dev/null
+++ b/plug-ins/imagemap/imap_csim_lex.c
@@ -0,0 +1,2054 @@
+
+#line 3 "<stdout>"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer csim__create_buffer
+#define yy_delete_buffer csim__delete_buffer
+#define yy_flex_debug csim__flex_debug
+#define yy_init_buffer csim__init_buffer
+#define yy_flush_buffer csim__flush_buffer
+#define yy_load_buffer_state csim__load_buffer_state
+#define yy_switch_to_buffer csim__switch_to_buffer
+#define yyin csim_in
+#define yyleng csim_leng
+#define yylex csim_lex
+#define yylineno csim_lineno
+#define yyout csim_out
+#define yyrestart csim_restart
+#define yytext csim_text
+#define yywrap csim_wrap
+#define yyalloc csim_alloc
+#define yyrealloc csim_realloc
+#define yyfree csim_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 36
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE csim_restart(csim_in )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t csim_leng;
+
+extern FILE *csim_in, *csim_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up csim_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up csim_text again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via csim_restart()), so that the user can continue scanning by
+ * just pointing csim_in at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when csim_text is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t csim_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow csim_wrap()'s to do buffer switches
+ * instead of setting up a fresh csim_in. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void csim_restart (FILE *input_file );
+void csim__switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE csim__create_buffer (FILE *file,int size );
+void csim__delete_buffer (YY_BUFFER_STATE b );
+void csim__flush_buffer (YY_BUFFER_STATE b );
+void csim_push_buffer_state (YY_BUFFER_STATE new_buffer );
+void csim_pop_buffer_state (void );
+
+static void csim_ensure_buffer_stack (void );
+static void csim__load_buffer_state (void );
+static void csim__init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER csim__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE csim__scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE csim__scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE csim__scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *csim_alloc (yy_size_t );
+void *csim_realloc (void *,yy_size_t );
+void csim_free (void * );
+
+#define yy_new_buffer csim__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ csim_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ csim__create_buffer(csim_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ csim_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ csim__create_buffer(csim_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define csim_wrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *csim_in = (FILE *) 0, *csim_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int csim_lineno;
+
+int csim_lineno = 1;
+
+extern char *csim_text;
+#define yytext_ptr csim_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up csim_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ csim_leng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 32
+#define YY_END_OF_BUFFER 33
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[154] =
+ { 0,
+ 29, 29, 28, 28, 0, 0, 33, 31, 30, 30,
+ 26, 29, 29, 31, 29, 31, 31, 31, 31, 29,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 28,
+ 27, 32, 32, 32, 30, 29, 29, 29, 29, 0,
+ 0, 0, 0, 0, 0, 29, 29, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 28,
+ 0, 0, 0, 0, 0, 23, 0, 0, 0, 0,
+ 0, 6, 12, 0, 0, 0, 0, 0, 0, 7,
+ 0, 0, 0, 0, 4, 13, 3, 15, 0, 0,
+ 0, 24, 14, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 8, 0, 10, 17, 9, 25, 22,
+ 0, 0, 18, 11, 0, 21, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 20, 0, 0, 0,
+ 19, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 2, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 5, 6, 7, 8, 1, 1, 1, 1,
+ 1, 1, 9, 1, 10, 11, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 14, 1, 15,
+ 1, 16, 1, 1, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 1, 1, 26, 27, 28, 29, 30,
+ 1, 31, 32, 33, 34, 35, 36, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 37, 38, 39, 40,
+
+ 41, 42, 43, 44, 45, 1, 1, 46, 47, 48,
+ 49, 50, 1, 51, 52, 53, 54, 55, 56, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[57] =
+ { 0,
+ 1, 1, 2, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[158] =
+ { 0,
+ 0, 0, 315, 314, 54, 55, 318, 322, 57, 64,
+ 322, 58, 49, 36, 61, 301, 47, 46, 47, 71,
+ 56, 58, 69, 71, 61, 70, 74, 60, 78, 0,
+ 322, 295, 322, 294, 113, 97, 111, 116, 106, 96,
+ 293, 95, 109, 100, 105, 289, 288, 110, 115, 114,
+ 109, 113, 117, 131, 125, 124, 113, 124, 126, 0,
+ 290, 289, 158, 137, 287, 322, 153, 151, 141, 152,
+ 154, 322, 322, 156, 148, 154, 152, 153, 153, 322,
+ 161, 158, 153, 178, 286, 322, 291, 322, 168, 173,
+ 174, 322, 322, 186, 174, 191, 177, 191, 193, 198,
+
+ 192, 284, 285, 186, 187, 187, 199, 191, 189, 192,
+ 322, 192, 196, 322, 283, 322, 322, 322, 322, 322,
+ 197, 212, 322, 322, 230, 322, 209, 214, 230, 220,
+ 219, 224, 224, 238, 236, 242, 322, 231, 234, 233,
+ 322, 234, 241, 276, 239, 322, 240, 253, 258, 260,
+ 90, 322, 322, 308, 311, 314, 316
+ } ;
+
+static yyconst flex_int16_t yy_def[158] =
+ { 0,
+ 153, 1, 154, 154, 155, 155, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 156,
+ 153, 157, 153, 157, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 156,
+ 157, 157, 157, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 157, 157, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+
+ 153, 157, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 0, 153, 153, 153, 153
+ } ;
+
+static yyconst flex_int16_t yy_nxt[379] =
+ { 0,
+ 8, 9, 10, 9, 8, 11, 8, 8, 8, 12,
+ 13, 14, 15, 8, 16, 8, 17, 18, 19, 8,
+ 20, 8, 8, 21, 22, 8, 23, 24, 25, 8,
+ 8, 26, 27, 28, 8, 29, 17, 18, 19, 8,
+ 20, 8, 8, 21, 22, 8, 23, 24, 25, 8,
+ 8, 26, 27, 28, 8, 29, 33, 33, 35, 35,
+ 35, 39, 40, 34, 34, 35, 35, 35, 36, 38,
+ 37, 36, 42, 37, 44, 45, 48, 43, 38, 46,
+ 46, 38, 40, 47, 50, 51, 49, 52, 54, 38,
+ 57, 58, 42, 55, 44, 45, 48, 43, 38, 53,
+
+ 56, 38, 59, 152, 50, 51, 49, 52, 54, 39,
+ 57, 58, 64, 55, 35, 35, 35, 38, 39, 53,
+ 56, 36, 59, 37, 46, 46, 38, 66, 47, 67,
+ 68, 38, 64, 69, 70, 71, 72, 38, 73, 74,
+ 75, 79, 80, 81, 82, 83, 38, 66, 76, 67,
+ 68, 38, 77, 69, 70, 71, 72, 78, 73, 74,
+ 75, 79, 80, 81, 82, 83, 86, 84, 76, 88,
+ 89, 90, 77, 85, 91, 92, 93, 78, 94, 95,
+ 96, 97, 98, 99, 100, 101, 86, 84, 104, 88,
+ 89, 90, 105, 102, 91, 92, 93, 106, 94, 95,
+
+ 96, 97, 98, 99, 100, 101, 107, 108, 104, 109,
+ 110, 111, 105, 112, 113, 114, 116, 106, 117, 118,
+ 119, 120, 121, 122, 123, 124, 107, 108, 126, 109,
+ 110, 111, 127, 112, 113, 114, 116, 130, 117, 118,
+ 119, 120, 121, 122, 123, 124, 128, 131, 126, 129,
+ 132, 135, 127, 133, 134, 136, 137, 130, 138, 139,
+ 140, 141, 142, 143, 144, 145, 128, 131, 147, 129,
+ 132, 135, 148, 133, 134, 136, 137, 149, 138, 139,
+ 140, 141, 142, 143, 144, 145, 150, 151, 147, 146,
+ 125, 115, 148, 62, 103, 62, 87, 149, 84, 62,
+
+ 47, 47, 65, 63, 62, 41, 150, 151, 30, 30,
+ 30, 32, 32, 32, 60, 60, 61, 153, 61, 31,
+ 31, 7, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153
+ } ;
+
+static yyconst flex_int16_t yy_chk[379] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 5, 6, 9, 9,
+ 9, 13, 14, 5, 6, 10, 10, 10, 12, 13,
+ 12, 15, 17, 15, 18, 19, 21, 17, 12, 20,
+ 20, 15, 14, 20, 22, 23, 21, 24, 25, 13,
+ 27, 28, 17, 26, 18, 19, 21, 17, 12, 24,
+
+ 26, 15, 29, 151, 22, 23, 21, 24, 25, 36,
+ 27, 28, 40, 26, 35, 35, 35, 36, 39, 24,
+ 26, 37, 29, 37, 38, 38, 39, 42, 38, 43,
+ 44, 37, 40, 45, 48, 49, 50, 36, 51, 52,
+ 53, 55, 56, 57, 58, 59, 39, 42, 54, 43,
+ 44, 37, 54, 45, 48, 49, 50, 54, 51, 52,
+ 53, 55, 56, 57, 58, 59, 64, 63, 54, 67,
+ 68, 69, 54, 63, 70, 71, 74, 54, 75, 76,
+ 77, 78, 79, 81, 82, 83, 64, 84, 89, 67,
+ 68, 69, 90, 84, 70, 71, 74, 91, 75, 76,
+
+ 77, 78, 79, 81, 82, 83, 94, 95, 89, 96,
+ 97, 98, 90, 99, 100, 101, 104, 91, 105, 106,
+ 107, 108, 109, 110, 112, 113, 94, 95, 121, 96,
+ 97, 98, 122, 99, 100, 101, 104, 127, 105, 106,
+ 107, 108, 109, 110, 112, 113, 125, 128, 121, 125,
+ 129, 131, 122, 130, 130, 132, 133, 127, 134, 135,
+ 136, 138, 139, 140, 142, 143, 125, 128, 145, 125,
+ 129, 131, 147, 130, 130, 132, 133, 148, 134, 135,
+ 136, 138, 139, 140, 142, 143, 149, 150, 145, 144,
+ 115, 103, 147, 102, 87, 85, 65, 148, 62, 61,
+
+ 47, 46, 41, 34, 32, 16, 149, 150, 154, 154,
+ 154, 155, 155, 155, 156, 156, 157, 7, 157, 4,
+ 3, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int csim__flex_debug;
+int csim__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *csim_text;
+#line 1 "imap_csim.l"
+#line 2 "imap_csim.l"
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2000 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_csim_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+#define YY_NO_INPUT 1
+
+
+#line 641 "<stdout>"
+
+#define INITIAL 0
+#define quoted_string 1
+#define comment 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int csim_lex_destroy (void );
+
+int csim_get_debug (void );
+
+void csim_set_debug (int debug_flag );
+
+YY_EXTRA_TYPE csim_get_extra (void );
+
+void csim_set_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *csim_get_in (void );
+
+void csim_set_in (FILE * in_str );
+
+FILE *csim_get_out (void );
+
+void csim_set_out (FILE * out_str );
+
+yy_size_t csim_get_leng (void );
+
+char *csim_get_text (void );
+
+int csim_get_lineno (void );
+
+void csim_set_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int csim_wrap (void );
+#else
+extern int csim_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( csim_text, csim_leng, 1, csim_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( csim_in )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( csim_in ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, csim_in))==0 && ferror(csim_in)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(csim_in); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int csim_lex (void);
+
+#define YY_DECL int csim_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after csim_text and csim_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 47 "imap_csim.l"
+
+
+#line 826 "<stdout>"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! csim_in )
+ csim_in = stdin;
+
+ if ( ! csim_out )
+ csim_out = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ csim_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ csim__create_buffer(csim_in,YY_BUF_SIZE );
+ }
+
+ csim__load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of csim_text. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 154 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 322 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 49 "imap_csim.l"
+{
+ BEGIN(comment);
+ return AUTHOR;
+ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 54 "imap_csim.l"
+{
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 59 "imap_csim.l"
+{
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 64 "imap_csim.l"
+{
+ BEGIN(INITIAL);
+ return END_COMMENT;
+ }
+ YY_BREAK
+case 5:
+*yy_cp = (yy_hold_char); /* undo effects of setting up csim_text */
+(yy_c_buf_p) = yy_cp -= 3;
+YY_DO_BEFORE_ACTION; /* set up csim_text again */
+YY_RULE_SETUP
+#line 69 "imap_csim.l"
+{
+ csim_lval.id = g_strndup (csim_text, csim_leng);
+ return STRING;
+ }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 74 "imap_csim.l"
+return IMG;
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 76 "imap_csim.l"
+return SRC;
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 78 "imap_csim.l"
+return WIDTH;
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 80 "imap_csim.l"
+return HEIGHT;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 82 "imap_csim.l"
+return BORDER;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 84 "imap_csim.l"
+return USEMAP;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 86 "imap_csim.l"
+return START_MAP;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 88 "imap_csim.l"
+return END_MAP;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 90 "imap_csim.l"
+return NAME;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 92 "imap_csim.l"
+return AREA;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 94 "imap_csim.l"
+return SHAPE;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 96 "imap_csim.l"
+return COORDS;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 98 "imap_csim.l"
+return TARGET;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 100 "imap_csim.l"
+return ONMOUSEOVER;
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 102 "imap_csim.l"
+return ONMOUSEOUT;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 104 "imap_csim.l"
+return ONFOCUS;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 106 "imap_csim.l"
+return ONBLUR;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 108 "imap_csim.l"
+return ALT;
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 110 "imap_csim.l"
+return HREF;
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 112 "imap_csim.l"
+return NOHREF;
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 114 "imap_csim.l"
+{
+ BEGIN(quoted_string);
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 118 "imap_csim.l"
+{
+ BEGIN(INITIAL);
+ return STRING;
+ }
+ YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+#line 123 "imap_csim.l"
+{
+ csim_lval.id = g_strndup (csim_text, csim_leng);
+ }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 127 "imap_csim.l"
+{
+ csim_lval.value = g_ascii_strtod (csim_text, NULL);
+ return FLOAT;
+ }
+ YY_BREAK
+case 30:
+/* rule 30 can match eol */
+YY_RULE_SETUP
+#line 132 "imap_csim.l"
+; /* Eat white space */
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 134 "imap_csim.l"
+return *csim_text;
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 136 "imap_csim.l"
+ECHO;
+ YY_BREAK
+#line 1099 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(quoted_string):
+case YY_STATE_EOF(comment):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed csim_in at a new source and called
+ * csim_lex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = csim_in;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( csim_wrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * csim_text, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of csim_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ csim_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ csim_restart(csim_in );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) csim_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 154 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 154 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 153);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ csim_restart(csim_in );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( csim_wrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve csim_text */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void csim_restart (FILE * input_file )
+{
+ if ( ! YY_CURRENT_BUFFER ){
+ csim_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ csim__create_buffer(csim_in,YY_BUF_SIZE );
+ }
+
+ csim__init_buffer(YY_CURRENT_BUFFER,input_file );
+ csim__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void csim__switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * csim_pop_buffer_state();
+ * csim_push_buffer_state(new_buffer);
+ */
+ csim_ensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ csim__load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (csim_wrap()) processing, but the only time this flag
+ * is looked at is after csim_wrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void csim__load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ csim_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE csim__create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) csim_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in csim__create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) csim_alloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in csim__create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ csim__init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with csim__create_buffer()
+ *
+ */
+ void csim__delete_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ csim_free((void *) b->yy_ch_buf );
+
+ csim_free((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a csim_restart() or at EOF.
+ */
+ static void csim__init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ csim__flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then csim__init_buffer was _probably_
+ * called from csim_restart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void csim__flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ csim__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void csim_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ csim_ensure_buffer_stack();
+
+ /* This block is copied from csim__switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from csim__switch_to_buffer. */
+ csim__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void csim_pop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ csim__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ csim__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void csim_ensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)csim_alloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in csim_ensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)csim_realloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in csim_ensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE csim__scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) csim_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in csim__scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ csim__switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to csim_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * csim__scan_bytes() instead.
+ */
+YY_BUFFER_STATE csim__scan_string (yyconst char * yystr )
+{
+ return csim__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to csim_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE csim__scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) csim_alloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in csim__scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = csim__scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in csim__scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up csim_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ csim_text[csim_leng] = (yy_hold_char); \
+ (yy_c_buf_p) = csim_text + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ csim_leng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int csim_get_lineno (void)
+{
+ return csim_lineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *csim_get_in (void)
+{
+ return csim_in;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *csim_get_out (void)
+{
+ return csim_out;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t csim_get_leng (void)
+{
+ return csim_leng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *csim_get_text (void)
+{
+ return csim_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void csim_set_lineno (int line_number )
+{
+ csim_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see csim__switch_to_buffer
+ */
+void csim_set_in (FILE * in_str )
+{
+ csim_in = in_str ;
+}
+
+void csim_set_out (FILE * out_str )
+{
+ csim_out = out_str ;
+}
+
+int csim_get_debug (void)
+{
+ return csim__flex_debug;
+}
+
+void csim_set_debug (int bdebug )
+{
+ csim__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from csim_lex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ csim_in = stdin;
+ csim_out = stdout;
+#else
+ csim_in = (FILE *) 0;
+ csim_out = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * csim_lex_init()
+ */
+ return 0;
+}
+
+/* csim_lex_destroy is for both reentrant and non-reentrant scanners. */
+int csim_lex_destroy (void)
+{
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ csim__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ csim_pop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ csim_free((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * csim_lex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *csim_alloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *csim_realloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void csim_free (void * ptr )
+{
+ free( (char *) ptr ); /* see csim_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 136 "imap_csim.l"
+
+
+
+
diff --git a/plug-ins/imagemap/imap_csim_parse.c b/plug-ins/imagemap/imap_csim_parse.c
new file mode 100644
index 0000000..b6411ac
--- /dev/null
+++ b/plug-ins/imagemap/imap_csim_parse.c
@@ -0,0 +1,2131 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.6.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse csim_parse
+#define yylex csim_lex
+#define yyerror csim_error
+#define yylval csim_lval
+#define yychar csim_char
+#define yydebug csim_debug
+#define yynerrs csim_nerrs
+
+/* Copy the first part of user declarations. */
+/* Line 336 of yacc.c */
+#line 1 "imap_csim.y"
+
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int csim_lex(void);
+extern int csim_restart(FILE *csim_in);
+static void csim_error(char* s);
+static gchar * unescape_text(gchar *input);
+
+static enum {UNDEFINED, RECTANGLE, CIRCLE, POLYGON} current_type;
+static Object_t *current_object;
+static MapInfo_t *_map_info;
+
+
+/* Line 336 of yacc.c */
+#line 123 "y.tab.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef CSIM_Y_TAB_H
+# define CSIM_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int csim_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ IMG = 258,
+ SRC = 259,
+ WIDTH = 260,
+ HEIGHT = 261,
+ BORDER = 262,
+ USEMAP = 263,
+ START_MAP = 264,
+ END_MAP = 265,
+ NAME = 266,
+ AREA = 267,
+ SHAPE = 268,
+ COORDS = 269,
+ ALT = 270,
+ HREF = 271,
+ NOHREF = 272,
+ TARGET = 273,
+ ONMOUSEOVER = 274,
+ ONMOUSEOUT = 275,
+ ONFOCUS = 276,
+ ONBLUR = 277,
+ AUTHOR = 278,
+ DESCRIPTION = 279,
+ BEGIN_COMMENT = 280,
+ END_COMMENT = 281,
+ FLOAT = 282,
+ STRING = 283
+ };
+#endif
+/* Tokens. */
+#define IMG 258
+#define SRC 259
+#define WIDTH 260
+#define HEIGHT 261
+#define BORDER 262
+#define USEMAP 263
+#define START_MAP 264
+#define END_MAP 265
+#define NAME 266
+#define AREA 267
+#define SHAPE 268
+#define COORDS 269
+#define ALT 270
+#define HREF 271
+#define NOHREF 272
+#define TARGET 273
+#define ONMOUSEOVER 274
+#define ONMOUSEOUT 275
+#define ONFOCUS 276
+#define ONBLUR 277
+#define AUTHOR 278
+#define DESCRIPTION 279
+#define BEGIN_COMMENT 280
+#define END_COMMENT 281
+#define FLOAT 282
+#define STRING 283
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 350 of yacc.c */
+#line 49 "imap_csim.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 350 of yacc.c */
+#line 229 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE csim_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int csim_parse (void *YYPARSE_PARAM);
+#else
+int csim_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int csim_parse (void);
+#else
+int csim_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !CSIM_Y_TAB_H */
+
+/* Copy the second part of user declarations. */
+
+/* Line 353 of yacc.c */
+#line 257 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 5
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 84
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 33
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 31
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 53
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 106
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 283
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 32, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 29, 30, 31, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 9, 17, 18, 21, 23, 25, 29,
+ 33, 37, 41, 45, 47, 49, 56, 57, 60, 62,
+ 64, 66, 70, 74, 78, 79, 82, 87, 89, 92,
+ 93, 96, 98, 100, 102, 104, 106, 108, 110, 112,
+ 114, 116, 120, 124, 128, 131, 132, 135, 139, 143,
+ 147, 151, 155, 159
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 34, 0, -1, 35, 41, 42, 47, 63, -1, 29,
+ 3, 4, 30, 28, 36, 49, -1, -1, 36, 37,
+ -1, 38, -1, 39, -1, 7, 30, 40, -1, 8,
+ 30, 28, -1, 15, 30, 28, -1, 5, 30, 40,
+ -1, 6, 30, 40, -1, 27, -1, 28, -1, 29,
+ 9, 11, 30, 28, 31, -1, -1, 42, 43, -1,
+ 45, -1, 46, -1, 44, -1, 25, 28, 26, -1,
+ 23, 28, 26, -1, 24, 28, 26, -1, -1, 47,
+ 48, -1, 29, 12, 50, 49, -1, 31, -1, 32,
+ 31, -1, -1, 50, 51, -1, 52, -1, 53, -1,
+ 54, -1, 55, -1, 57, -1, 58, -1, 59, -1,
+ 60, -1, 61, -1, 62, -1, 13, 30, 28, -1,
+ 14, 30, 28, -1, 16, 30, 28, -1, 17, 56,
+ -1, -1, 30, 28, -1, 15, 30, 28, -1, 18,
+ 30, 28, -1, 19, 30, 28, -1, 20, 30, 28,
+ -1, 21, 30, 28, -1, 22, 30, 28, -1, 29,
+ 10, 31, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 66, 66, 69, 76, 77, 80, 81, 82, 83,
+ 84, 87, 93, 99, 103, 110, 117, 118, 121, 122,
+ 123, 126, 132, 139, 150, 151, 154, 161, 162, 165,
+ 166, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 181, 199, 259, 270, 275, 276, 282, 289, 296,
+ 303, 310, 317, 324
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "IMG", "SRC", "WIDTH", "HEIGHT",
+ "BORDER", "USEMAP", "START_MAP", "END_MAP", "NAME", "AREA", "SHAPE",
+ "COORDS", "ALT", "HREF", "NOHREF", "TARGET", "ONMOUSEOVER", "ONMOUSEOUT",
+ "ONFOCUS", "ONBLUR", "AUTHOR", "DESCRIPTION", "BEGIN_COMMENT",
+ "END_COMMENT", "FLOAT", "STRING", "'<'", "'='", "'>'", "'/'", "$accept",
+ "csim_file", "image", "image_tags", "image_tag", "image_width",
+ "image_height", "integer_value", "start_map", "comment_lines",
+ "comment_line", "real_comment", "author_line", "description_line",
+ "area_list", "area", "xhtml_close", "tag_list", "tag", "shape_tag",
+ "coords_tag", "href_tag", "nohref_tag", "optional_value", "alt_tag",
+ "target_tag", "onmouseover_tag", "onmouseout_tag", "onfocus_tag",
+ "onblur_tag", "end_map", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 60,
+ 61, 62, 47
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 33, 34, 35, 36, 36, 37, 37, 37, 37,
+ 37, 38, 39, 40, 40, 41, 42, 42, 43, 43,
+ 43, 44, 45, 46, 47, 47, 48, 49, 49, 50,
+ 50, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 60, 61, 62, 63
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 5, 7, 0, 2, 1, 1, 3, 3,
+ 3, 3, 3, 1, 1, 6, 0, 2, 1, 1,
+ 1, 3, 3, 3, 0, 2, 4, 1, 2, 0,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 3, 3, 2, 0, 2, 3, 3, 3,
+ 3, 3, 3, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 0, 0, 0, 1, 0, 16, 0, 0,
+ 24, 0, 0, 0, 0, 0, 17, 20, 18, 19,
+ 0, 4, 0, 0, 0, 0, 0, 25, 2, 0,
+ 0, 22, 23, 21, 0, 29, 0, 0, 0, 0,
+ 0, 27, 0, 5, 6, 7, 3, 15, 53, 0,
+ 0, 0, 0, 0, 0, 28, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 26, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 13, 14,
+ 11, 12, 8, 9, 10, 0, 0, 0, 0, 0,
+ 44, 0, 0, 0, 0, 0, 41, 42, 47, 43,
+ 46, 48, 49, 50, 51, 52
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 2, 3, 29, 43, 44, 45, 80, 7, 10,
+ 16, 17, 18, 19, 20, 27, 46, 49, 67, 68,
+ 69, 70, 71, 90, 72, 73, 74, 75, 76, 77,
+ 28
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -29
+static const yytype_int8 yypact[] =
+{
+ -21, 22, 28, 2, 29, -29, 23, -29, 4, 24,
+ -19, 8, 7, 10, 11, 12, -29, -29, -29, -29,
+ 13, -29, 15, 18, 19, 20, -3, -29, -29, -5,
+ 16, -29, -29, -29, 17, -29, 21, 25, 26, 27,
+ 30, -29, 31, -29, -29, -29, -29, -29, -29, -2,
+ -6, -6, -6, 33, 35, -29, 34, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, 47, 48, 49, 50, 51,
+ -29, 52, 53, 54, 55, 56, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -29, -29, -29, -29, -29, -29, -29, -28, -29, -29,
+ -29, -29, -29, -29, -29, -29, -8, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 36, 37, 38, 39, 13, 14, 15, 34, 1, 35,
+ 40, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 78, 79, 81, 82, 4, 41, 42, 5, 41,
+ 42, 6, 9, 8, 11, 12, 21, 22, 23, 24,
+ 25, 66, 26, 30, 31, 32, 33, 47, 48, 0,
+ 0, 50, 0, 0, 0, 51, 52, 53, 0, 0,
+ 54, 83, 55, 84, 85, 0, 86, 87, 88, 89,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-29))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int8 yycheck[] =
+{
+ 5, 6, 7, 8, 23, 24, 25, 10, 29, 12,
+ 15, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 27, 28, 51, 52, 3, 31, 32, 0, 31,
+ 32, 29, 9, 4, 30, 11, 28, 30, 28, 28,
+ 28, 49, 29, 28, 26, 26, 26, 31, 31, -1,
+ -1, 30, -1, -1, -1, 30, 30, 30, -1, -1,
+ 30, 28, 31, 28, 30, -1, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 29, 34, 35, 3, 0, 29, 41, 4, 9,
+ 42, 30, 11, 23, 24, 25, 43, 44, 45, 46,
+ 47, 28, 30, 28, 28, 28, 29, 48, 63, 36,
+ 28, 26, 26, 26, 10, 12, 5, 6, 7, 8,
+ 15, 31, 32, 37, 38, 39, 49, 31, 31, 50,
+ 30, 30, 30, 30, 30, 31, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 49, 51, 52, 53,
+ 54, 55, 57, 58, 59, 60, 61, 62, 27, 28,
+ 40, 40, 40, 28, 28, 30, 30, 30, 30, 30,
+ 56, 30, 30, 30, 30, 30, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+/* Line 1787 of yacc.c */
+#line 70 "imap_csim.y"
+ {
+ g_strreplace(&_map_info->image_name, (yyvsp[(5) - (7)].id));
+ g_free ((yyvsp[(5) - (7)].id));
+ }
+ break;
+
+ case 8:
+/* Line 1787 of yacc.c */
+#line 82 "imap_csim.y"
+ {}
+ break;
+
+ case 9:
+/* Line 1787 of yacc.c */
+#line 83 "imap_csim.y"
+ { g_free ((yyvsp[(3) - (3)].id)); }
+ break;
+
+ case 10:
+/* Line 1787 of yacc.c */
+#line 84 "imap_csim.y"
+ { g_free ((yyvsp[(3) - (3)].id)); }
+ break;
+
+ case 11:
+/* Line 1787 of yacc.c */
+#line 88 "imap_csim.y"
+ {
+ _map_info->old_image_width = (yyvsp[(3) - (3)].val);
+ }
+ break;
+
+ case 12:
+/* Line 1787 of yacc.c */
+#line 94 "imap_csim.y"
+ {
+ _map_info->old_image_height = (yyvsp[(3) - (3)].val);
+ }
+ break;
+
+ case 13:
+/* Line 1787 of yacc.c */
+#line 100 "imap_csim.y"
+ {
+ (yyval.val) = (gint) (yyvsp[(1) - (1)].value);
+ }
+ break;
+
+ case 14:
+/* Line 1787 of yacc.c */
+#line 104 "imap_csim.y"
+ {
+ (yyval.val) = (gint) g_ascii_strtod ((yyvsp[(1) - (1)].id), NULL);
+ g_free ((yyvsp[(1) - (1)].id));
+ }
+ break;
+
+ case 15:
+/* Line 1787 of yacc.c */
+#line 111 "imap_csim.y"
+ {
+ g_strreplace(&_map_info->title, (yyvsp[(5) - (6)].id));
+ g_free ((yyvsp[(5) - (6)].id));
+ }
+ break;
+
+ case 21:
+/* Line 1787 of yacc.c */
+#line 127 "imap_csim.y"
+ {
+ g_free ((yyvsp[(2) - (3)].id));
+ }
+ break;
+
+ case 22:
+/* Line 1787 of yacc.c */
+#line 133 "imap_csim.y"
+ {
+ g_strreplace(&_map_info->author, (yyvsp[(2) - (3)].id));
+ g_free ((yyvsp[(2) - (3)].id));
+ }
+ break;
+
+ case 23:
+/* Line 1787 of yacc.c */
+#line 140 "imap_csim.y"
+ {
+ gchar *description;
+
+ description = g_strconcat(_map_info->description, (yyvsp[(2) - (3)].id), "\n",
+ NULL);
+ g_strreplace(&_map_info->description, description);
+ g_free ((yyvsp[(2) - (3)].id));
+ }
+ break;
+
+ case 26:
+/* Line 1787 of yacc.c */
+#line 155 "imap_csim.y"
+ {
+ if (current_type != UNDEFINED)
+ add_shape(current_object);
+ }
+ break;
+
+ case 41:
+/* Line 1787 of yacc.c */
+#line 182 "imap_csim.y"
+ {
+ if (!g_ascii_strcasecmp((yyvsp[(3) - (3)].id), "RECT")) {
+ current_object = create_rectangle(0, 0, 0, 0);
+ current_type = RECTANGLE;
+ } else if (!g_ascii_strcasecmp((yyvsp[(3) - (3)].id), "CIRCLE")) {
+ current_object = create_circle(0, 0, 0);
+ current_type = CIRCLE;
+ } else if (!g_ascii_strcasecmp((yyvsp[(3) - (3)].id), "POLY")) {
+ current_object = create_polygon(NULL);
+ current_type = POLYGON;
+ } else if (!g_ascii_strcasecmp((yyvsp[(3) - (3)].id), "DEFAULT")) {
+ current_type = UNDEFINED;
+ }
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 42:
+/* Line 1787 of yacc.c */
+#line 200 "imap_csim.y"
+ {
+ char *p;
+ if (current_type == RECTANGLE) {
+ Rectangle_t *rectangle;
+
+ rectangle = ObjectToRectangle(current_object);
+ p = strtok((yyvsp[(3) - (3)].id), ",");
+ rectangle->x = atoi(p);
+ p = strtok(NULL, ",");
+ rectangle->y = atoi(p);
+ p = strtok(NULL, ",");
+ rectangle->width = atoi(p) - rectangle->x;
+ p = strtok(NULL, ",");
+ rectangle->height = atoi(p) - rectangle->y;
+ } else if (current_type == CIRCLE) {
+ Circle_t *circle;
+
+ circle = ObjectToCircle(current_object);
+ p = strtok((yyvsp[(3) - (3)].id), ",");
+ circle->x = atoi(p);
+ p = strtok(NULL, ",");
+ circle->y = atoi(p);
+ p = strtok(NULL, ",");
+ circle->r = atoi(p);
+ } else if (current_type == POLYGON) {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GList *points;
+ GdkPoint *point, *first;
+ gint x, y;
+
+ p = strtok((yyvsp[(3) - (3)].id), ",");
+ x = atoi(p);
+ p = strtok(NULL, ",");
+ y = atoi(p);
+ point = new_point(x, y);
+ points = g_list_append(NULL, (gpointer) point);
+
+ while(1) {
+ p = strtok(NULL, ",");
+ if (!p)
+ break;
+ x = atoi(p);
+ p = strtok(NULL, ",");
+ y = atoi(p);
+ point = new_point(x, y);
+ points = g_list_append(points, (gpointer) point);
+ }
+ /* Remove last point if duplicate */
+ first = (GdkPoint*) points->data;
+ polygon->points = points;
+ if (first->x == point->x && first->y == point->y)
+ polygon_remove_last_point(polygon);
+ polygon->points = points;
+ }
+
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 43:
+/* Line 1787 of yacc.c */
+#line 260 "imap_csim.y"
+ {
+ if (current_type == UNDEFINED) {
+ g_strreplace(&_map_info->default_url, (yyvsp[(3) - (3)].id));
+ } else {
+ object_set_url(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ }
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 44:
+/* Line 1787 of yacc.c */
+#line 271 "imap_csim.y"
+ {
+ }
+ break;
+
+ case 46:
+/* Line 1787 of yacc.c */
+#line 277 "imap_csim.y"
+ {
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 47:
+/* Line 1787 of yacc.c */
+#line 283 "imap_csim.y"
+ {
+ object_set_comment(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 48:
+/* Line 1787 of yacc.c */
+#line 290 "imap_csim.y"
+ {
+ object_set_target(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 49:
+/* Line 1787 of yacc.c */
+#line 297 "imap_csim.y"
+ {
+ object_set_mouse_over(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 50:
+/* Line 1787 of yacc.c */
+#line 304 "imap_csim.y"
+ {
+ object_set_mouse_out(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 51:
+/* Line 1787 of yacc.c */
+#line 311 "imap_csim.y"
+ {
+ object_set_focus(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+ case 52:
+/* Line 1787 of yacc.c */
+#line 318 "imap_csim.y"
+ {
+ object_set_blur(current_object, unescape_text((yyvsp[(3) - (3)].id)));
+ g_free ((yyvsp[(3) - (3)].id));
+ }
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 1831 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2048 of yacc.c */
+#line 327 "imap_csim.y"
+
+
+static void
+csim_error(char* s)
+{
+ extern FILE *csim_in;
+ csim_restart(csim_in);
+}
+
+gboolean
+load_csim (const char* filename)
+{
+ gboolean status;
+ extern FILE *csim_in;
+ csim_in = g_fopen(filename, "r");
+ if (csim_in) {
+ _map_info = get_map_info();
+ status = !csim_parse();
+ fclose(csim_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
+
+static gchar*
+unescape_text (gchar *input)
+{
+ /*
+ * We "unescape" simple things "in place", knowing that unescaped
+ * strings always are shorter than the original input.
+ *
+ * It is a shame there is no g_markup_unescape_text() function, but
+ * instead you have to create a full GMarkupParser/Context.
+ */
+ struct token {
+ const char *escaped;
+ const char unescaped;
+ };
+ const struct token tab[] = {
+ { "&quot;", '"' },
+ { "&apos;", '\'' },
+ { "&amp;", '&' },
+ { "&lt;", '<' },
+ { "&gt;", '>' }
+ };
+
+ size_t i;
+ for (i = 0; i < (sizeof tab / sizeof tab[0]); i++)
+ {
+ const size_t escaped_len = strlen (tab[i].escaped);
+ char *p;
+
+ /* FIXME: The following code does not perform a UTF-8 substring
+ search. */
+ for (p = strstr (input, tab[i].escaped);
+ p != NULL;
+ p = strstr (p, tab[i].escaped))
+ {
+ size_t copy_len;
+ *p++ = tab[i].unescaped;
+ copy_len = strlen (p) - escaped_len + 2;
+ memmove (p, p + escaped_len - 1, copy_len);
+ if (*p == 0)
+ break;
+ }
+ }
+
+ return input;
+}
+
diff --git a/plug-ins/imagemap/imap_csim_parse.h b/plug-ins/imagemap/imap_csim_parse.h
new file mode 100644
index 0000000..f83d108
--- /dev/null
+++ b/plug-ins/imagemap/imap_csim_parse.h
@@ -0,0 +1,142 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef CSIM_Y_TAB_H
+# define CSIM_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int csim_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ IMG = 258,
+ SRC = 259,
+ WIDTH = 260,
+ HEIGHT = 261,
+ BORDER = 262,
+ USEMAP = 263,
+ START_MAP = 264,
+ END_MAP = 265,
+ NAME = 266,
+ AREA = 267,
+ SHAPE = 268,
+ COORDS = 269,
+ ALT = 270,
+ HREF = 271,
+ NOHREF = 272,
+ TARGET = 273,
+ ONMOUSEOVER = 274,
+ ONMOUSEOUT = 275,
+ ONFOCUS = 276,
+ ONBLUR = 277,
+ AUTHOR = 278,
+ DESCRIPTION = 279,
+ BEGIN_COMMENT = 280,
+ END_COMMENT = 281,
+ FLOAT = 282,
+ STRING = 283
+ };
+#endif
+/* Tokens. */
+#define IMG 258
+#define SRC 259
+#define WIDTH 260
+#define HEIGHT 261
+#define BORDER 262
+#define USEMAP 263
+#define START_MAP 264
+#define END_MAP 265
+#define NAME 266
+#define AREA 267
+#define SHAPE 268
+#define COORDS 269
+#define ALT 270
+#define HREF 271
+#define NOHREF 272
+#define TARGET 273
+#define ONMOUSEOVER 274
+#define ONMOUSEOUT 275
+#define ONFOCUS 276
+#define ONBLUR 277
+#define AUTHOR 278
+#define DESCRIPTION 279
+#define BEGIN_COMMENT 280
+#define END_COMMENT 281
+#define FLOAT 282
+#define STRING 283
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2049 of yacc.c */
+#line 49 "imap_csim.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 2049 of yacc.c */
+#line 120 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE csim_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int csim_parse (void *YYPARSE_PARAM);
+#else
+int csim_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int csim_parse (void);
+#else
+int csim_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !CSIM_Y_TAB_H */
diff --git a/plug-ins/imagemap/imap_default_dialog.c b/plug-ins/imagemap/imap_default_dialog.c
new file mode 100644
index 0000000..5fff183
--- /dev/null
+++ b/plug-ins/imagemap/imap_default_dialog.c
@@ -0,0 +1,184 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <libgimp/gimpui.h>
+
+#include "imap_default_dialog.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static void
+dialog_response (GtkWidget *widget,
+ gint response_id,
+ DefaultDialog_t *dialog)
+{
+ switch (response_id)
+ {
+ case GTK_RESPONSE_APPLY:
+ if (dialog->apply_cb)
+ dialog->apply_cb (dialog->apply_cb_data);
+ else if (dialog->ok_cb)
+ dialog->ok_cb (dialog->ok_cb_data);
+ break;
+
+ case GTK_RESPONSE_OK:
+ gtk_widget_hide (dialog->dialog);
+ if (dialog->ok_cb)
+ dialog->ok_cb (dialog->ok_cb_data);
+ break;
+
+ default:
+ gtk_widget_hide (dialog->dialog);
+ if (dialog->cancel_cb)
+ dialog->cancel_cb (dialog->cancel_cb_data);
+ break;
+ }
+}
+
+void
+default_dialog_set_ok_cb(DefaultDialog_t *dialog, void (*ok_cb)(gpointer),
+ gpointer ok_cb_data)
+{
+ dialog->ok_cb = ok_cb;
+ dialog->ok_cb_data = ok_cb_data;
+}
+
+void
+default_dialog_set_apply_cb(DefaultDialog_t *dialog,
+ void (*apply_cb)(gpointer),
+ gpointer apply_cb_data)
+{
+ dialog->apply_cb = apply_cb;
+ dialog->apply_cb_data = apply_cb_data;
+}
+
+void
+default_dialog_set_cancel_cb(DefaultDialog_t *dialog,
+ void (*cancel_cb)(gpointer),
+ gpointer cancel_cb_data)
+{
+ dialog->cancel_cb = cancel_cb;
+ dialog->cancel_cb_data = cancel_cb_data;
+}
+
+DefaultDialog_t *
+make_default_dialog (const gchar *title)
+{
+ DefaultDialog_t *data = g_new0 (DefaultDialog_t, 1);
+
+ data->ok_cb = NULL;
+ data->apply_cb = NULL;
+ data->cancel_cb = NULL;
+
+ data->dialog = gimp_dialog_new (title, PLUG_IN_ROLE,
+ get_dialog(), 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+ NULL);
+
+ data->apply = gtk_dialog_add_button (GTK_DIALOG (data->dialog),
+ _("_Apply"), GTK_RESPONSE_APPLY);
+
+ data->cancel = gtk_dialog_add_button (GTK_DIALOG (data->dialog),
+ _("_Cancel"), GTK_RESPONSE_CANCEL);
+
+ data->ok = gtk_dialog_add_button (GTK_DIALOG (data->dialog),
+ _("_OK"), GTK_RESPONSE_OK);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (data->dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_APPLY,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ g_signal_connect (data->dialog, "response",
+ G_CALLBACK (dialog_response),
+ data);
+ g_signal_connect (data->dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &data->dialog);
+
+ data->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (data->vbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (data->dialog))),
+ data->vbox, TRUE, TRUE, 0);
+ gtk_widget_show (data->vbox);
+
+ return data;
+}
+
+void
+default_dialog_show(DefaultDialog_t *dialog)
+{
+ gtk_widget_show(dialog->dialog);
+}
+
+void
+default_dialog_hide_cancel_button(DefaultDialog_t *dialog)
+{
+ gtk_widget_hide(dialog->cancel);
+}
+
+void
+default_dialog_hide_apply_button(DefaultDialog_t *dialog)
+{
+ gtk_widget_hide(dialog->apply);
+}
+
+void
+default_dialog_hide_help_button(DefaultDialog_t *dialog)
+{
+ /* gtk_widget_hide(dialog->help); */
+}
+
+void
+default_dialog_set_title(DefaultDialog_t *dialog, const gchar *title)
+{
+ gtk_window_set_title(GTK_WINDOW(dialog->dialog), title);
+}
+
+void
+default_dialog_set_label(DefaultDialog_t *dialog, const gchar *text)
+{
+ GtkWidget *label = gtk_label_new(text);
+
+ gtk_box_pack_start (GTK_BOX (dialog->vbox), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+}
+
+GtkWidget*
+default_dialog_add_table(DefaultDialog_t *dialog, gint rows, gint cols)
+{
+ GtkWidget *table = gtk_table_new (rows, cols, FALSE);
+
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+
+ gtk_box_pack_start (GTK_BOX (dialog->vbox), table, TRUE, TRUE, 0);
+ gtk_widget_show (table);
+
+ return table;
+}
diff --git a/plug-ins/imagemap/imap_default_dialog.h b/plug-ins/imagemap/imap_default_dialog.h
new file mode 100644
index 0000000..a1b4ac5
--- /dev/null
+++ b/plug-ins/imagemap/imap_default_dialog.h
@@ -0,0 +1,59 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_DEFAULT_DIALOG_H
+#define _IMAP_DEFAULT_DIALOG_H
+
+typedef struct
+{
+ GtkWidget *dialog;
+ GtkWidget *vbox;
+ GtkWidget *ok;
+ GtkWidget *apply;
+ GtkWidget *cancel;
+ void (*ok_cb)(gpointer);
+ gpointer ok_cb_data;
+ void (*apply_cb)(gpointer);
+ gpointer apply_cb_data;
+ void (*cancel_cb)(gpointer);
+ gpointer cancel_cb_data;
+} DefaultDialog_t;
+
+DefaultDialog_t *make_default_dialog(const gchar *title);
+void default_dialog_set_ok_cb(DefaultDialog_t *dialog, void (*ok_cb)(gpointer),
+ gpointer ok_cb_data);
+void default_dialog_set_apply_cb(DefaultDialog_t *dialog,
+ void (*apply_cb)(gpointer),
+ gpointer apply_cb_data);
+void default_dialog_set_cancel_cb(DefaultDialog_t *dialog,
+ void (*ok_cb)(gpointer),
+ gpointer ok_cb_data);
+void default_dialog_show(DefaultDialog_t *dialog);
+void default_dialog_hide_cancel_button(DefaultDialog_t *dialog);
+void default_dialog_hide_apply_button(DefaultDialog_t *dialog);
+void default_dialog_hide_help_button(DefaultDialog_t *dialog);
+void default_dialog_set_title(DefaultDialog_t *dialog, const gchar *title);
+void default_dialog_set_label(DefaultDialog_t *dialog, const gchar *text);
+GtkWidget *default_dialog_add_table(DefaultDialog_t *dialog, gint rows,
+ gint cols);
+
+#endif /* _IMAP_DEFAULT_DIALOG_H */
diff --git a/plug-ins/imagemap/imap_edit_area_info.c b/plug-ins/imagemap/imap_edit_area_info.c
new file mode 100644
index 0000000..9ed596d
--- /dev/null
+++ b/plug-ins/imagemap/imap_edit_area_info.c
@@ -0,0 +1,560 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <string.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "imap_browse.h"
+#include "imap_commands.h"
+#include "imap_default_dialog.h"
+#include "imap_edit_area_info.h"
+#include "imap_main.h"
+#include "imap_stock.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static gboolean callback_lock;
+
+static void select_web_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_ftp_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_gopher_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_other_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_file_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_wais_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_telnet_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+static void select_email_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param);
+
+
+static gchar*
+relative_filter(const char *name, gpointer data)
+{
+ AreaInfoDialog_t *param = (AreaInfoDialog_t*) data;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->relative_link)))
+ return g_path_get_basename(name);
+ return g_strdup (name);
+}
+
+static void
+url_changed (GtkWidget *widget,
+ gpointer data)
+{
+ AreaInfoDialog_t *param = (AreaInfoDialog_t*) data;
+ const gchar *url = gtk_entry_get_text (GTK_ENTRY (param->url));
+ GtkWidget *button;
+
+ if (! g_ascii_strncasecmp (url, "http://", sizeof ("http://") - 1) ||
+ ! g_ascii_strncasecmp (url, "https://", sizeof ( "https://") - 1))
+ button = param->web_site;
+ else if (! g_ascii_strncasecmp (url, "ftp://", sizeof ("ftp://") - 1))
+ button = param->ftp_site;
+ else if (! g_ascii_strncasecmp (url, "gopher://", sizeof ("gopher://") - 1))
+ button = param->gopher;
+ else if (! g_ascii_strncasecmp (url, "file:/", sizeof ("file:/") - 1))
+ button = param->file;
+ else if (! g_ascii_strncasecmp (url, "wais://", sizeof ("wais://") - 1))
+ button = param->wais;
+ else if (! g_ascii_strncasecmp (url, "telnet://", sizeof ("telnet://") - 1))
+ button = param->telnet;
+ else if (! g_ascii_strncasecmp (url, "mailto:", sizeof ("mailto:") - 1))
+ button = param->email;
+ else
+ button = param->other;
+
+ callback_lock = TRUE;
+ g_signal_handlers_block_by_func (param->web_site, G_CALLBACK (select_web_cb), data);
+ g_signal_handlers_block_by_func (param->ftp_site, G_CALLBACK (select_ftp_cb), data);
+ g_signal_handlers_block_by_func (param->gopher, G_CALLBACK (select_gopher_cb), data);
+ g_signal_handlers_block_by_func (param->other, G_CALLBACK (select_other_cb), data);
+ g_signal_handlers_block_by_func (param->file, G_CALLBACK (select_file_cb), data);
+ g_signal_handlers_block_by_func (param->wais, G_CALLBACK (select_wais_cb), data);
+ g_signal_handlers_block_by_func (param->telnet, G_CALLBACK (select_telnet_cb), data);
+ g_signal_handlers_block_by_func (param->email, G_CALLBACK (select_email_cb), data);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ g_signal_handlers_unblock_by_func (param->web_site, G_CALLBACK (select_web_cb), data);
+ g_signal_handlers_unblock_by_func (param->ftp_site, G_CALLBACK (select_ftp_cb), data);
+ g_signal_handlers_unblock_by_func (param->gopher, G_CALLBACK (select_gopher_cb), data);
+ g_signal_handlers_unblock_by_func (param->other, G_CALLBACK (select_other_cb), data);
+ g_signal_handlers_unblock_by_func (param->file, G_CALLBACK (select_file_cb), data);
+ g_signal_handlers_unblock_by_func (param->wais, G_CALLBACK (select_wais_cb), data);
+ g_signal_handlers_unblock_by_func (param->telnet, G_CALLBACK (select_telnet_cb), data);
+ g_signal_handlers_unblock_by_func (param->email, G_CALLBACK (select_email_cb), data);
+}
+
+static void
+set_url (GtkWidget *widget,
+ AreaInfoDialog_t *param,
+ const gchar *prefix)
+{
+ if (callback_lock)
+ {
+ callback_lock = FALSE;
+ }
+ else
+ {
+ if (gtk_widget_get_state (widget) & GTK_STATE_SELECTED)
+ {
+ char *p;
+ gchar *url = g_strdup (gtk_entry_get_text (GTK_ENTRY(param->url)));
+
+ p = strstr (url, "//"); /* 'https://' */
+ if (p)
+ {
+ p += 2;
+ }
+ else
+ {
+ p = strchr (url, ':'); /* 'mailto:' */
+ if (p)
+ {
+ p++;
+ if (*p == '/') /* 'file:/' */
+ p++;
+ }
+ else
+ {
+ p = url;
+ }
+ }
+ p = g_strconcat (prefix, p, NULL);
+ gtk_entry_set_text (GTK_ENTRY(param->url), p);
+ g_free (p);
+ g_free (url);
+ }
+ }
+ gtk_widget_grab_focus(param->url);
+}
+
+static void
+select_web_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "https://");
+}
+
+static void
+select_ftp_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url(widget, param, "ftp://");
+}
+
+static void
+select_gopher_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "gopher://");
+}
+
+static void
+select_other_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "");
+}
+
+static void
+select_file_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "file:/");
+}
+
+static void
+select_wais_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "wais://");
+}
+
+static void
+select_telnet_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "telnet://");
+}
+
+static void
+select_email_cb (GtkWidget *widget,
+ AreaInfoDialog_t *param)
+{
+ set_url (widget, param, "mailto:");
+}
+
+static void
+append_page (GtkWidget *notebook, GtkWidget *page, const gchar *icon_name,
+ const gchar *label_name)
+{
+ GtkWidget *hbox, *icon, *label;
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_widget_show(hbox);
+
+ icon = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
+ gtk_widget_show (icon);
+
+ label = gtk_label_new_with_mnemonic (label_name);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, hbox);
+}
+
+static void
+create_link_tab(AreaInfoDialog_t *dialog, GtkWidget *notebook)
+{
+ BrowseWidget_t *browse;
+ GtkWidget *table, *label;
+ GtkWidget *subtable, *frame;
+ GSList *group;
+
+ table = gtk_table_new(11, 1, FALSE);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_widget_show(table);
+
+ frame = gimp_frame_new(_("Link Type"));
+ gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 0, 1);
+ gtk_widget_show(frame);
+
+ subtable = gtk_table_new(2, 4, FALSE);
+ gtk_container_add (GTK_CONTAINER(frame), subtable);
+ gtk_widget_show(subtable);
+
+ dialog->web_site = create_radio_button_in_table(subtable, NULL, 0, 0,
+ _("_Web Site"));
+ g_signal_connect(dialog->web_site, "toggled",
+ G_CALLBACK (select_web_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->web_site));
+
+ dialog->ftp_site = create_radio_button_in_table(subtable, group, 0, 1,
+ _("_Ftp Site"));
+ g_signal_connect(dialog->ftp_site, "toggled",
+ G_CALLBACK (select_ftp_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->ftp_site));
+
+ dialog->gopher = create_radio_button_in_table(subtable, group, 0, 2,
+ _("_Gopher"));
+ g_signal_connect(dialog->gopher, "toggled",
+ G_CALLBACK (select_gopher_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->gopher));
+
+ dialog->other = create_radio_button_in_table(subtable, group, 0, 3,
+ _("Ot_her"));
+ g_signal_connect(dialog->other, "toggled",
+ G_CALLBACK (select_other_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->other));
+
+ dialog->file = create_radio_button_in_table(subtable, group, 1, 0,
+ _("F_ile"));
+ g_signal_connect(dialog->file, "toggled",
+ G_CALLBACK (select_file_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->file));
+
+ dialog->wais = create_radio_button_in_table(subtable, group, 1, 1,
+ _("WAI_S"));
+ g_signal_connect(dialog->wais, "toggled",
+ G_CALLBACK (select_wais_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->wais));
+
+ dialog->telnet = create_radio_button_in_table(subtable, group, 1, 2,
+ _("Tel_net"));
+ g_signal_connect(dialog->telnet, "toggled",
+ G_CALLBACK (select_telnet_cb), (gpointer) dialog);
+ group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(dialog->telnet));
+
+ dialog->email = create_radio_button_in_table(subtable, group, 1, 3,
+ _("e-_mail"));
+ g_signal_connect(dialog->email, "toggled",
+ G_CALLBACK (select_email_cb), (gpointer) dialog);
+
+ label = create_label_in_table(
+ table, 2, 0,
+ _("_URL to activate when this area is clicked: (required)"));
+
+ browse = browse_widget_new( _("Select HTML file"));
+ browse_widget_set_filter(browse, relative_filter, (gpointer) dialog);
+ gtk_table_attach_defaults(GTK_TABLE(table), browse->hbox, 0, 1, 3, 4);
+ dialog->url = browse->file;
+ g_signal_connect(dialog->url, "changed", G_CALLBACK(url_changed),
+ dialog);
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), dialog->url);
+
+ dialog->relative_link = create_check_button_in_table(table, 4, 0,
+ _("Relati_ve link"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->relative_link),
+ TRUE);
+
+ label = create_label_in_table(
+ table, 6, 0,
+ _("_Target frame name/ID: (optional - used for FRAMES only)"));
+ dialog->target = create_entry_in_table(table, label, 7, 0);
+
+ label = create_label_in_table(table, 9, 0, _("ALT te_xt: (optional)"));
+ dialog->comment = create_entry_in_table(table, label, 10, 0);
+
+ append_page (notebook, table, GIMP_ICON_WEB, _("_Link"));
+}
+
+static void
+geometry_changed(Object_t *obj, gpointer data)
+{
+ AreaInfoDialog_t *dialog = (AreaInfoDialog_t*) data;
+ if (dialog->geometry_lock) {
+ dialog->geometry_lock = FALSE;
+ } else {
+ if (dialog->obj == obj) {
+ object_update_info_widget(obj, dialog->infotab);
+ obj->class->assign(obj, dialog->clone);
+ }
+ }
+}
+
+static void
+toggle_preview_cb(GtkWidget *widget, AreaInfoDialog_t *param)
+{
+ param->preview = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ edit_area_info_dialog_emit_geometry_signal(param);
+}
+
+static void
+create_info_tab(AreaInfoDialog_t *dialog, GtkWidget *notebook)
+{
+ GtkWidget *vbox, *frame, *preview;
+ Object_t *obj = dialog->obj;
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
+ gtk_widget_show(vbox);
+
+ frame = gimp_frame_new(_("Dimensions"));
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show(frame);
+
+ preview = gtk_check_button_new_with_mnemonic(_("Pre_view"));
+ g_signal_connect(preview, "toggled",
+ G_CALLBACK (toggle_preview_cb), (gpointer) dialog);
+ gtk_box_pack_start(GTK_BOX(vbox), preview, FALSE, FALSE, 0);
+ gtk_widget_show(preview);
+
+ dialog->infotab = obj->class->create_info_widget(frame);
+
+ append_page (notebook, vbox, obj->class->get_stock_icon_name (),
+ gettext (obj->class->name));
+}
+
+static void
+create_java_script_tab(AreaInfoDialog_t *dialog, GtkWidget *notebook)
+{
+ GtkWidget *vbox, *table, *label;
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
+ gtk_widget_show(vbox);
+
+ table = gtk_table_new(11, 1, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_widget_show(table);
+
+ label = create_label_in_table(table, 0, 0, "o_nMouseover:");
+ dialog->mouse_over = create_entry_in_table(table, label, 1, 0);
+
+ label = create_label_in_table(table, 3, 0, "on_Mouseout:");
+ dialog->mouse_out = create_entry_in_table(table, label, 4, 0);
+
+ label = create_label_in_table(table, 6, 0, "on_Focus (HTML 4.0):");
+ dialog->focus = create_entry_in_table(table, label, 7, 0);
+
+ label = create_label_in_table(table, 9, 0, "on_Blur (HTML 4.0):");
+ dialog->blur = create_entry_in_table(table, label, 10, 0);
+
+ append_page (notebook, vbox, IMAP_STOCK_JAVA, _("_JavaScript"));
+}
+
+static gboolean
+object_was_changed(AreaInfoDialog_t *dialog)
+{
+ Object_t *clone = dialog->clone;
+ Object_t *obj = dialog->obj;
+ gint old_x, old_y, old_width, old_height;
+ gint new_x, new_y, new_width, new_height;
+
+ object_get_dimensions(clone, &old_x, &old_y, &old_width, &old_height);
+ object_get_dimensions(obj, &new_x, &new_y, &new_width, &new_height);
+
+ return new_x != old_x || new_y != old_y || new_width != old_width ||
+ new_height != old_height || clone->selected != obj->selected;
+}
+
+static void
+edit_area_apply_cb(gpointer data)
+{
+ AreaInfoDialog_t *param = (AreaInfoDialog_t*) data;
+ Object_t *obj = param->obj;
+
+ object_set_url(obj, gtk_entry_get_text(GTK_ENTRY(param->url)));
+ object_set_target(obj, gtk_entry_get_text(GTK_ENTRY(param->target)));
+ object_set_comment(obj, gtk_entry_get_text(GTK_ENTRY(param->comment)));
+ object_set_mouse_over(obj,
+ gtk_entry_get_text(GTK_ENTRY(param->mouse_over)));
+ object_set_mouse_out(obj, gtk_entry_get_text(GTK_ENTRY(param->mouse_out)));
+ object_set_focus(obj, gtk_entry_get_text(GTK_ENTRY(param->focus)));
+ object_set_blur(obj, gtk_entry_get_text(GTK_ENTRY(param->blur)));
+ object_update(obj, param->infotab);
+ update_shape(obj);
+
+ if (object_was_changed(param))
+ preview_redraw();
+}
+
+static void
+edit_area_ok_cb(gpointer data)
+{
+ AreaInfoDialog_t *param = (AreaInfoDialog_t*) data;
+ Object_t *obj = param->obj;
+
+ object_list_remove_geometry_cb(obj->list, param->geometry_cb_id);
+
+ /* Fix me: nasty hack */
+ if (param->add)
+ command_list_add(edit_object_command_new(obj));
+
+ edit_area_apply_cb(data);
+ object_unlock(obj);
+ object_unref(param->clone);
+}
+
+static void
+edit_area_cancel_cb(gpointer data)
+{
+ AreaInfoDialog_t *dialog = (AreaInfoDialog_t*) data;
+ Object_t *obj = dialog->obj;
+ gboolean changed = object_was_changed(dialog);
+ gboolean selected = obj->selected;
+
+ object_list_remove_geometry_cb(obj->list, dialog->geometry_cb_id);
+ object_unlock(obj);
+ object_assign(dialog->clone, obj);
+ obj->selected = selected;
+ object_unref(dialog->clone);
+
+ if (changed)
+ preview_redraw();
+}
+
+static void
+switch_page(GtkWidget *widget, gpointer page, gint page_num,
+ gpointer data)
+{
+ AreaInfoDialog_t *param = (AreaInfoDialog_t*) data;
+ if (page_num == 0) {
+ gtk_widget_grab_focus(param->url);
+ } else if (page_num == 1) {
+ Object_t *obj = param->obj;
+ obj->class->set_initial_focus(obj, param->infotab);
+ } else {
+ gtk_widget_grab_focus(param->mouse_over);
+ }
+}
+
+AreaInfoDialog_t*
+create_edit_area_info_dialog(Object_t *obj)
+{
+ AreaInfoDialog_t *data = g_new(AreaInfoDialog_t, 1);
+ GtkWidget *notebook;
+
+ data->geometry_lock = FALSE;
+ data->preview = FALSE;
+ data->obj = obj;
+ data->browse = NULL;
+ data->dialog = make_default_dialog(_("Area Settings"));
+ default_dialog_set_ok_cb(data->dialog, edit_area_ok_cb, data);
+ default_dialog_set_apply_cb(data->dialog, edit_area_apply_cb, data);
+ default_dialog_set_cancel_cb(data->dialog, edit_area_cancel_cb, data);
+
+ data->notebook = notebook = gtk_notebook_new();
+ g_signal_connect_after(notebook, "switch-page",
+ G_CALLBACK(switch_page), (gpointer) data);
+
+ gtk_box_pack_start(GTK_BOX(data->dialog->vbox), notebook, TRUE, TRUE, 0);
+ create_link_tab(data, notebook);
+ create_info_tab(data, notebook);
+ create_java_script_tab(data, notebook);
+ gtk_widget_show(notebook);
+
+ return data;
+}
+
+void
+edit_area_info_dialog_show(AreaInfoDialog_t *dialog, Object_t *obj,
+ gboolean add)
+{
+ gchar *title;
+
+ object_unlock(dialog->obj);
+ object_lock(obj);
+ dialog->obj = obj;
+ dialog->clone = object_clone(obj);
+ dialog->add = add;
+ object_fill_info_tab(obj, dialog->infotab);
+ gtk_entry_set_text(GTK_ENTRY(dialog->url), obj->url);
+ gtk_entry_set_text(GTK_ENTRY(dialog->target), obj->target);
+ gtk_entry_set_text(GTK_ENTRY(dialog->comment), obj->comment);
+ gtk_entry_set_text(GTK_ENTRY(dialog->mouse_over), obj->mouse_over);
+ gtk_entry_set_text(GTK_ENTRY(dialog->mouse_out), obj->mouse_out);
+ gtk_entry_set_text(GTK_ENTRY(dialog->focus), obj->focus);
+ gtk_entry_set_text(GTK_ENTRY(dialog->blur), obj->blur);
+ gtk_widget_grab_focus(dialog->url);
+
+ dialog->geometry_cb_id =
+ object_list_add_geometry_cb(obj->list, geometry_changed, dialog);
+
+ title = g_strdup_printf (_("Area #%d Settings"),
+ object_get_position_in_list(obj) + 1);
+ default_dialog_set_title(dialog->dialog, title);
+ g_free (title);
+ default_dialog_show(dialog->dialog);
+}
+
+void
+edit_area_info_dialog_emit_geometry_signal(AreaInfoDialog_t *dialog)
+{
+ if (dialog->preview) {
+ dialog->geometry_lock = TRUE;
+ object_emit_geometry_signal(dialog->obj);
+ }
+}
diff --git a/plug-ins/imagemap/imap_edit_area_info.h b/plug-ins/imagemap/imap_edit_area_info.h
new file mode 100644
index 0000000..fbf45fb
--- /dev/null
+++ b/plug-ins/imagemap/imap_edit_area_info.h
@@ -0,0 +1,66 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_EDIT_AREA_INFO_H
+#define _IMAP_EDIT_AREA_INFO_H
+
+typedef struct AreaInfoDialog_t AreaInfoDialog_t;
+
+#include "imap_default_dialog.h"
+#include "imap_object.h"
+
+struct AreaInfoDialog_t {
+ DefaultDialog_t *dialog;
+ Object_t *obj;
+ Object_t *clone;
+ gboolean add;
+ gboolean geometry_lock;
+ gboolean preview;
+
+ GtkWidget *notebook;
+ GtkWidget *web_site;
+ GtkWidget *ftp_site;
+ GtkWidget *gopher;
+ GtkWidget *other;
+ GtkWidget *file;
+ GtkWidget *wais;
+ GtkWidget *telnet;
+ GtkWidget *email;
+ GtkWidget *url;
+ GtkWidget *relative_link;
+ GtkWidget *target;
+ GtkWidget *comment;
+ GtkWidget *mouse_over;
+ GtkWidget *mouse_out;
+ GtkWidget *focus;
+ GtkWidget *blur;
+ GtkWidget *browse;
+ gpointer infotab;
+ gpointer geometry_cb_id;
+};
+
+AreaInfoDialog_t *create_edit_area_info_dialog(Object_t *obj);
+void edit_area_info_dialog_show(AreaInfoDialog_t *dialog, Object_t *obj,
+ gboolean add);
+void edit_area_info_dialog_emit_geometry_signal(AreaInfoDialog_t *dialog);
+
+#endif /* _IMAP_EDIT_AREA_INFO_H */
diff --git a/plug-ins/imagemap/imap_file.c b/plug-ins/imagemap/imap_file.c
new file mode 100644
index 0000000..35ff832
--- /dev/null
+++ b/plug-ins/imagemap/imap_file.c
@@ -0,0 +1,180 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <libgimp/gimpui.h>
+
+#include "imap_file.h"
+#include "imap_main.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static void
+open_cb (GtkWidget *dialog,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ if (! g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+ {
+ do_file_error_dialog (_("Error opening file"), filename);
+ g_free (filename);
+ return;
+ }
+
+ load (filename);
+ g_free (filename);
+ }
+
+ gtk_widget_hide (dialog);
+}
+
+void
+do_file_open_dialog (void)
+{
+ static GtkWidget *dialog;
+
+ if (! dialog)
+ {
+ dialog =
+ gtk_file_chooser_dialog_new (_("Load Image Map"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &dialog);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (open_cb),
+ dialog);
+ }
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+save_cb (GtkWidget *dialog,
+ gint response_id,
+ gpointer data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+ save_as (filename);
+ g_free (filename);
+ }
+
+ gtk_widget_hide (dialog);
+}
+
+void
+do_file_save_as_dialog (void)
+{
+ static GtkWidget *dialog;
+
+ if (! dialog)
+ {
+ gchar *filename;
+
+ dialog = gtk_file_chooser_dialog_new (_("Save Image Map"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
+ TRUE);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &dialog);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (save_cb),
+ dialog);
+
+ /* Suggest a filename based on the image name.
+ * The image name is in UTF-8 encoding.
+ */
+ filename = g_strconcat (get_image_name(), ".map", NULL);
+
+ if (filename)
+ {
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog),
+ filename);
+ g_free (filename);
+ }
+ }
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+void
+do_file_error_dialog (const char *error,
+ const char *filename)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new_with_markup
+ (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ error,
+ gimp_filename_to_utf8 (filename));
+
+ g_signal_connect_swapped (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy),
+ dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+}
diff --git a/plug-ins/imagemap/imap_file.h b/plug-ins/imagemap/imap_file.h
new file mode 100644
index 0000000..c661eaa
--- /dev/null
+++ b/plug-ins/imagemap/imap_file.h
@@ -0,0 +1,34 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_FILE_H
+#define _IMAP_FILE_H
+
+void do_file_open_dialog(void);
+void do_file_save_as_dialog(void);
+void do_file_error_dialog(const char *error, const char *filename);
+
+gboolean load_csim (const char* filename);
+gboolean load_cern (const char* filename);
+gboolean load_ncsa (const char* filename);
+
+#endif /* _IMAP_FILE_H */
diff --git a/plug-ins/imagemap/imap_grid.c b/plug-ins/imagemap/imap_grid.c
new file mode 100644
index 0000000..48c6a54
--- /dev/null
+++ b/plug-ins/imagemap/imap_grid.c
@@ -0,0 +1,414 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "imap_grid.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_preview.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+typedef enum {GRID_HIDDEN, GRID_LINES, GRID_CROSSES} GridType_t;
+
+typedef struct {
+ DefaultDialog_t *dialog;
+ GtkWidget *type_frame;
+ GtkWidget *granularity_frame;
+ GtkWidget *offset_frame;
+ GtkWidget *snap;
+ GtkWidget *width;
+ GtkWidget *height;
+ GtkWidget *chain_width_height;
+ GtkWidget *left;
+ GtkWidget *top;
+ GtkWidget *chain_left_top;
+ GtkWidget *hidden;
+ GtkWidget *lines;
+ GtkWidget *crosses;
+ GtkWidget *preview;
+
+ gboolean enable_preview;
+} GridDialog_t;
+
+
+static gboolean grid_snap = FALSE;
+static gint grid_width = 15;
+static gint grid_height = 15;
+static gint grid_left = 0;
+static gint grid_top = 0;
+static GridType_t grid_type = GRID_LINES;
+
+static void
+grid_settings_ok_cb(gpointer data)
+{
+ GridDialog_t *param = (GridDialog_t*) data;
+ gboolean new_snap;
+
+ new_snap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->snap));
+ grid_width = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->width));
+ grid_height = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->height));
+ grid_left = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->left));
+ grid_top = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(param->top));
+
+ if (grid_snap != new_snap) {
+ grid_snap = new_snap;
+ menu_check_grid(grid_snap);
+ }
+ preview_redraw();
+}
+
+static void
+snap_toggled_cb(GtkWidget *widget, gpointer data)
+{
+ GridDialog_t *param = (GridDialog_t*) data;
+ gint sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
+ gtk_widget_set_sensitive(param->type_frame, sensitive);
+ gtk_widget_set_sensitive(param->granularity_frame, sensitive);
+ gtk_widget_set_sensitive(param->offset_frame, sensitive);
+ gtk_widget_set_sensitive(param->preview, sensitive);
+}
+
+static void
+type_toggled_cb(GtkWidget *widget, gpointer data)
+{
+ if (gtk_widget_get_state (widget) & GTK_STATE_SELECTED)
+ {
+ grid_type = GPOINTER_TO_INT (data);
+ preview_redraw();
+ }
+}
+
+static void
+toggle_preview_cb(GtkWidget *widget, GridDialog_t *param)
+{
+ param->enable_preview =
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+ preview_redraw();
+}
+
+static void
+grid_assign_value(GtkWidget *widget, gpointer data, gint *value)
+{
+ GridDialog_t *dialog = (GridDialog_t*) data;
+ if (dialog->enable_preview) {
+ *value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ preview_redraw(); /* Fix me! */
+ }
+}
+
+static void
+width_changed_cb(GtkWidget *widget, gpointer data)
+{
+ GridDialog_t *dialog = (GridDialog_t*) data;
+
+ grid_assign_value(widget, data, &grid_width);
+ if (gimp_chain_button_get_active(
+ GIMP_CHAIN_BUTTON(dialog->chain_width_height))) {
+ gint value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->height), value);
+ }
+}
+
+static void
+height_changed_cb(GtkWidget *widget, gpointer data)
+{
+ GridDialog_t *dialog = (GridDialog_t*) data;
+
+ grid_assign_value(widget, data, &grid_height);
+ if (gimp_chain_button_get_active(
+ GIMP_CHAIN_BUTTON(dialog->chain_width_height))) {
+ gint value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->width), value);
+ }
+}
+
+static void
+left_changed_cb(GtkWidget *widget, gpointer data)
+{
+ GridDialog_t *dialog = (GridDialog_t*) data;
+
+ grid_assign_value(widget, data, &grid_left);
+ if (gimp_chain_button_get_active(
+ GIMP_CHAIN_BUTTON(dialog->chain_left_top))) {
+ gint value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->top), value);
+ }
+}
+
+static void
+top_changed_cb(GtkWidget *widget, gpointer data)
+{
+ GridDialog_t *dialog = (GridDialog_t*) data;
+
+ grid_assign_value(widget, data, &grid_top);
+ if (gimp_chain_button_get_active(
+ GIMP_CHAIN_BUTTON(dialog->chain_left_top))) {
+ gint value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->left), value);
+ }
+}
+
+static GridDialog_t*
+create_grid_settings_dialog(void)
+{
+ GridDialog_t *data = g_new(GridDialog_t, 1);
+ DefaultDialog_t *dialog;
+ GtkWidget *main_table, *table, *label;
+ GtkWidget *frame;
+ GtkWidget *hbox;
+ GtkWidget *button;
+ GtkWidget *chain_button;
+
+ data->dialog = dialog = make_default_dialog(_("Grid Settings"));
+ default_dialog_set_ok_cb(dialog, grid_settings_ok_cb, (gpointer) data);
+ main_table = default_dialog_add_table(dialog, 4, 2);
+
+ data->snap = gtk_check_button_new_with_mnemonic(_("_Snap-to grid enabled"));
+ g_signal_connect(data->snap, "toggled",
+ G_CALLBACK (snap_toggled_cb), data);
+ gtk_table_attach_defaults(GTK_TABLE(main_table), data->snap, 0, 1, 0, 1);
+ gtk_widget_show(data->snap);
+
+ data->type_frame = frame = gimp_frame_new(_("Grid Visibility and Type"));
+ gtk_widget_show(frame);
+ gtk_table_attach_defaults(GTK_TABLE(main_table), frame, 0, 2, 1, 2);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+
+ button = gtk_radio_button_new_with_mnemonic_from_widget(NULL, _("_Hidden"));
+ data->hidden = button;
+ g_signal_connect(button, "toggled",
+ G_CALLBACK (type_toggled_cb), (gpointer) GRID_HIDDEN);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+
+ button = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(button), _("_Lines"));
+ data->lines = button;
+ g_signal_connect(button, "toggled",
+ G_CALLBACK (type_toggled_cb), (gpointer) GRID_LINES);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+
+ button = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(button), _("C_rosses"));
+ data->crosses = button;
+ g_signal_connect(button, "toggled",
+ G_CALLBACK (type_toggled_cb),
+ (gpointer) GRID_CROSSES);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show(button);
+
+ data->granularity_frame = frame = gimp_frame_new(_("Grid Granularity"));
+ gtk_table_attach_defaults(GTK_TABLE(main_table), frame, 0, 1, 2, 3);
+ table = gtk_table_new(2, 4, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ label = create_label_in_table(table, 0, 0, _("_Width"));
+ data->width = create_spin_button_in_table(table, label, 0, 1, 15, 1, 100);
+ g_signal_connect(data->width, "value-changed",
+ G_CALLBACK (width_changed_cb), (gpointer) data);
+ create_label_in_table(table, 0, 3, _("pixels"));
+
+ label = create_label_in_table(table, 1, 0, _("_Height"));
+ data->height = create_spin_button_in_table(table, label, 1, 1, 15, 1, 100);
+ g_signal_connect(data->height, "value-changed",
+ G_CALLBACK (height_changed_cb), (gpointer) data);
+ create_label_in_table(table, 1, 3, _("pixels"));
+
+ chain_button = gimp_chain_button_new(GIMP_CHAIN_RIGHT);
+ data->chain_width_height = chain_button;
+ gtk_table_attach_defaults(GTK_TABLE(table), chain_button, 2, 3, 0, 2);
+ gtk_widget_show(chain_button);
+
+ gtk_widget_show(table);
+ gtk_widget_show(frame);
+
+ data->offset_frame = frame = gimp_frame_new(_("Grid Offset"));
+ gtk_table_attach_defaults(GTK_TABLE(main_table), frame, 1, 2, 2, 3);
+ table = gtk_table_new(2, 3, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ label = create_label_in_table(table, 0, 2, _("pixels from l_eft"));
+ data->left = create_spin_button_in_table(table, label, 0, 0, 0, 0, 100);
+ g_signal_connect(data->left, "value-changed",
+ G_CALLBACK (left_changed_cb), (gpointer) data);
+
+ label = create_label_in_table(table, 1, 2, _("pixels from _top"));
+ data->top = create_spin_button_in_table(table, label, 1, 0, 0, 0, 100);
+ g_signal_connect(data->top, "value-changed",
+ G_CALLBACK (top_changed_cb), (gpointer) data);
+
+ chain_button = gimp_chain_button_new(GIMP_CHAIN_RIGHT);
+ data->chain_left_top = chain_button;
+ gtk_table_attach_defaults(GTK_TABLE(table), chain_button, 1, 2, 0, 2);
+ gtk_widget_show(chain_button);
+
+ data->preview = create_check_button_in_table(main_table, 3, 0,
+ _("_Preview"));
+ g_signal_connect(data->preview, "toggled",
+ G_CALLBACK (toggle_preview_cb), (gpointer) data);
+ gtk_widget_show(data->preview);
+
+ snap_toggled_cb(data->snap, data);
+
+ gtk_widget_show(table);
+ gtk_widget_show(frame);
+
+ return data;
+}
+
+void
+do_grid_settings_dialog(void)
+{
+ static GridDialog_t* dialog;
+ GtkWidget *type;
+
+ if (!dialog)
+ dialog = create_grid_settings_dialog();
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->snap), grid_snap);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->width), grid_width);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->height), grid_height);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->left), grid_left);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->top), grid_top);
+
+ if (grid_type == GRID_HIDDEN)
+ type = dialog->hidden;
+ else if (grid_type == GRID_LINES)
+ type = dialog->lines;
+ else
+ type = dialog->crosses;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(type), TRUE);
+
+ default_dialog_show(dialog->dialog);
+}
+
+static void
+draw_lines(cairo_t *cr, gint width, gint height)
+{
+ gint x, y;
+ gdouble dash = 4.;
+
+ cairo_set_dash (cr, &dash, 1, 0.);
+ for (x = grid_left % grid_width; x < width; x += grid_width)
+ draw_line(cr, x, 1, x, height);
+ for (y = grid_top % grid_height; y < height; y += grid_height)
+ draw_line(cr, 1, y, width, y);
+}
+
+static void
+draw_crosses(cairo_t *cr, gint width, gint height)
+{
+ gint x, y;
+ gdouble dash[4] = { 7., grid_height - 7., 7., grid_width - 7. };
+
+ cairo_set_dash (cr, dash, 2, 4.5 - grid_top);
+ for (x = grid_left % grid_width; x < width; x += grid_width)
+ draw_line(cr, x, 1, x, height);
+ cairo_set_dash (cr, dash+2, 2, 4.5 - grid_left);
+ for (y = grid_top % grid_height; y < height; y += grid_height)
+ draw_line(cr, 1, y, width, y);
+}
+
+void
+draw_grid(cairo_t *cr, gint width, gint height)
+{
+ if (grid_snap && grid_type != GRID_HIDDEN)
+ {
+ cairo_save (cr);
+ if (grid_type == GRID_LINES)
+ {
+ draw_lines(cr, width, height);
+ }
+ else
+ {
+ draw_crosses(cr, width, height);
+ }
+ cairo_restore (cr);
+ }
+}
+
+void
+toggle_grid(void)
+{
+ grid_snap = !grid_snap;
+ preview_redraw();
+}
+
+static gint
+grid_nearest_x(gint x)
+{
+ return grid_left + (x - grid_left + grid_width / 2) / grid_width
+ * grid_width;
+}
+
+static gint
+grid_nearest_y(gint y)
+{
+ return grid_top + (y - grid_top + grid_height / 2) / grid_height
+ * grid_height;
+}
+
+void
+round_to_grid(gint *x, gint *y)
+{
+ if (grid_snap) {
+ *x = grid_nearest_x(*x);
+ *y = grid_nearest_y(*y);
+ }
+}
+
+gboolean
+grid_near_x(gint x)
+{
+ return grid_snap && grid_type != GRID_HIDDEN
+ && abs(grid_nearest_x(x) - x) <= 1;
+}
+
+gboolean
+grid_near_y(gint y)
+{
+ return grid_snap && grid_type != GRID_HIDDEN
+ && abs(grid_nearest_x(y) - y) <= 1;
+}
diff --git a/plug-ins/imagemap/imap_grid.h b/plug-ins/imagemap/imap_grid.h
new file mode 100644
index 0000000..84deb95
--- /dev/null
+++ b/plug-ins/imagemap/imap_grid.h
@@ -0,0 +1,34 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_GRID_H
+#define _IMAP_GRID_H
+
+void do_grid_settings_dialog (void);
+void draw_grid (cairo_t *cr, gint width, gint height);
+void toggle_grid (void);
+void round_to_grid (gint *x, gint *y);
+
+gboolean grid_near_x (gint x);
+gboolean grid_near_y (gint y);
+
+#endif /* _IMAP_GRID_H */
diff --git a/plug-ins/imagemap/imap_main.c b/plug-ins/imagemap/imap_main.c
new file mode 100644
index 0000000..8254a87
--- /dev/null
+++ b/plug-ins/imagemap/imap_main.c
@@ -0,0 +1,1306 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2006 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h> /* for keyboard values */
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "imap_about.h"
+#include "imap_circle.h"
+#include "imap_commands.h"
+#include "imap_default_dialog.h"
+#include "imap_edit_area_info.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_misc.h"
+#include "imap_object.h"
+#include "imap_polygon.h"
+#include "imap_preview.h"
+#include "imap_rectangle.h"
+#include "imap_selection.h"
+#include "imap_settings.h"
+#include "imap_source.h"
+#include "imap_statusbar.h"
+#include "imap_stock.h"
+#include "imap_string.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define MAX_ZOOM_FACTOR 8
+#define ZOOMED(x) (_zoom_factor * (x))
+#define GET_REAL_COORD(x) ((x) / _zoom_factor)
+
+static gint zoom_in (void);
+static gint zoom_out (void);
+
+
+/* Global variables */
+static MapInfo_t _map_info;
+static PreferencesData_t _preferences = {CSIM, TRUE, FALSE, TRUE, TRUE, FALSE,
+FALSE, TRUE, DEFAULT_UNDO_LEVELS, DEFAULT_MRU_SIZE};
+static MRU_t *_mru;
+
+static gint32 _drawable_id;
+static GdkCursorType _cursor = GDK_TOP_LEFT_ARROW;
+static gboolean _show_url = TRUE;
+static gchar *_filename = NULL;
+static gchar *_image_name;
+static gint _image_width;
+static gint _image_height;
+static GtkWidget *_dlg;
+static Preview_t *_preview;
+static Selection_t *_selection;
+static StatusBar_t *_statusbar;
+static ObjectList_t *_shapes;
+static gint _zoom_factor = 1;
+static gboolean (*_button_press_func)(GtkWidget*, GdkEventButton*, gpointer);
+static gpointer _button_press_param;
+
+/* Declare local functions. */
+static void query (void);
+static void run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+static gint dialog (gint32 drawable_id);
+
+const GimpPlugInInfo PLUG_IN_INFO = {
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ query, /* query_proc */
+ run, /* run_proc */
+};
+
+static int run_flag = 0;
+
+
+MAIN ()
+
+static void query(void)
+{
+ static const GimpParamDef args[] = {
+ {GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0) }"},
+ {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
+ {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
+ };
+ static const GimpParamDef *return_vals = NULL;
+ static int nreturn_vals = 0;
+
+ gimp_install_procedure(PLUG_IN_PROC,
+ N_("Create a clickable imagemap"),
+ "",
+ "Maurits Rijk",
+ "Maurits Rijk",
+ "1998-2005",
+ N_("_Image Map..."),
+ "RGB*, GRAY*, INDEXED*",
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (args), nreturn_vals,
+ args, return_vals);
+
+ gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Web");
+}
+
+static void
+run (const gchar *name,
+ gint n_params,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[1];
+ GimpRunMode run_mode;
+ gint32 drawable_id;
+ GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+
+ INIT_I18N ();
+ gegl_init (NULL, NULL);
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ run_mode = param[0].data.d_int32;
+ drawable_id = param[2].data.d_drawable;
+
+ _drawable_id = drawable_id;
+ _image_name = gimp_image_get_name(param[1].data.d_image);
+ _image_width = gimp_image_width(param[1].data.d_image);
+ _image_height = gimp_image_height(param[1].data.d_image);
+
+ _map_info.color = gimp_drawable_is_rgb(drawable_id);
+
+ if (run_mode == GIMP_RUN_INTERACTIVE) {
+ if (!dialog(drawable_id)) {
+ /* The dialog was closed, or something similarly evil happened. */
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+ }
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = status;
+}
+
+GtkWidget*
+get_dialog(void)
+{
+ return _dlg;
+}
+
+MRU_t*
+get_mru(void)
+{
+ if (!_mru)
+ _mru = mru_create();
+ return _mru;
+}
+
+MapInfo_t*
+get_map_info(void)
+{
+ return &_map_info;
+}
+
+PreferencesData_t*
+get_preferences(void)
+{
+ return &_preferences;
+}
+
+static void
+init_preferences(void)
+{
+ ColorSelData_t *colors = &_preferences.colors;
+
+ colors->normal_fg.red = 0;
+ colors->normal_fg.green = 0xFFFF;
+ colors->normal_fg.blue = 0;
+
+ colors->normal_bg.red = 0;
+ colors->normal_bg.green = 0;
+ colors->normal_bg.blue = 0xFFFF;
+
+ colors->selected_fg.red = 0xFFFF;
+ colors->selected_fg.green = 0;
+ colors->selected_fg.blue = 0;
+
+ colors->selected_bg.red = 0;
+ colors->selected_bg.green = 0;
+ colors->selected_bg.blue = 0xFFFF;
+
+ colors->interactive_fg.red = 0xFFFF;
+ colors->interactive_fg.green = 0;
+ colors->interactive_fg.blue = 0xFFFF;
+
+ colors->interactive_bg.red = 0xFFFF;
+ colors->interactive_bg.green = 0xFFFF;
+ colors->interactive_bg.blue = 0;
+
+ preferences_load(&_preferences);
+
+ mru_set_size(_mru, _preferences.mru_size);
+ command_list_set_undo_level(_preferences.undo_levels);
+}
+
+gint
+get_image_width(void)
+{
+ return _image_width;
+}
+
+gint
+get_image_height(void)
+{
+ return _image_height;
+}
+
+void
+set_busy_cursor(void)
+{
+ preview_set_cursor(_preview, GDK_WATCH);
+}
+
+void
+remove_busy_cursor(void)
+{
+ gdk_window_set_cursor(gtk_widget_get_window (_dlg), NULL);
+}
+
+static gint
+zoom_in(void)
+{
+ if (_zoom_factor < MAX_ZOOM_FACTOR) {
+ set_zoom(_zoom_factor + 1);
+ menu_set_zoom(_zoom_factor);
+ }
+ return _zoom_factor;
+}
+
+static gint
+zoom_out(void)
+{
+ if (_zoom_factor > 1) {
+ set_zoom(_zoom_factor - 1);
+ menu_set_zoom(_zoom_factor);
+ }
+ return _zoom_factor;
+}
+
+void
+set_zoom(gint zoom_factor)
+{
+ set_busy_cursor();
+ _zoom_factor = zoom_factor;
+ preview_zoom(_preview, zoom_factor);
+ statusbar_set_zoom(_statusbar, zoom_factor);
+ remove_busy_cursor();
+}
+
+gint
+get_real_coord(gint coord)
+{
+ return GET_REAL_COORD(coord);
+}
+
+void
+draw_line(cairo_t *cr, gint x1, gint y1, gint x2, gint y2)
+{
+ cairo_move_to (cr, ZOOMED (x1) + .5, ZOOMED (y1) + .5);
+ cairo_line_to (cr, ZOOMED (x2) + .5, ZOOMED (y2) + .5);
+ cairo_stroke (cr);
+}
+
+void
+draw_rectangle(cairo_t *cr, gboolean filled, gint x, gint y,
+ gint width, gint height)
+{
+ cairo_rectangle (cr, ZOOMED (x) + (filled ? 0. : .5),
+ ZOOMED (y) + (filled ? 0. : .5),
+ ZOOMED (width), ZOOMED (height));
+ if (filled)
+ cairo_fill (cr);
+ else
+ cairo_stroke (cr);
+}
+
+void
+draw_circle(cairo_t *cr, gint x, gint y, gint r)
+{
+ cairo_arc (cr, ZOOMED (x), ZOOMED (y), ZOOMED (r), 0., 2 * G_PI);
+ cairo_stroke (cr);
+}
+
+void
+draw_polygon(cairo_t *cr, GList *list)
+{
+ GList *p;
+
+ for (p = list; p; p = p->next) {
+ GdkPoint *src = (GdkPoint*) p->data;
+ cairo_line_to (cr, ZOOMED (src->x) + .5, ZOOMED (src->y) + .5);
+ }
+ cairo_close_path (cr);
+ cairo_stroke (cr);
+}
+
+void
+set_preview_color (GtkRadioAction *action, GtkRadioAction *current,
+ gpointer user_data)
+{
+ _map_info.show_gray = (gtk_radio_action_get_current_value (current) == 1);
+ set_zoom(_zoom_factor);
+}
+
+void
+preview_redraw(void)
+{
+ gtk_widget_queue_draw(_preview->preview);
+}
+
+void
+set_zoom_factor (GtkRadioAction *action, GtkRadioAction *current,
+ gpointer user_data)
+{
+ gint factor = gtk_radio_action_get_current_value (current);
+ set_zoom (factor + 1);
+}
+
+const gchar *
+get_image_name(void)
+{
+ return _image_name;
+}
+
+const char*
+get_filename(void)
+{
+ return _filename;
+}
+
+static gboolean
+arrow_on_button_press (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ if (gdk_event_triggers_context_menu ((GdkEvent *) event))
+ {
+ do_popup_menu (event);
+ }
+ else if (event->button == 1)
+ {
+ if (event->type == GDK_2BUTTON_PRESS)
+ edit_shape((gint) event->x, (gint) event->y);
+ else
+ select_shape(widget, event);
+ }
+
+ return FALSE;
+}
+
+static void
+set_arrow_func(void)
+{
+ _button_press_func = arrow_on_button_press;
+ _cursor = GDK_TOP_LEFT_ARROW;
+}
+
+static void
+set_object_func(gboolean (*func)(GtkWidget*, GdkEventButton*,
+ gpointer), gpointer param)
+{
+ _button_press_func = func;
+ _button_press_param = param;
+ _cursor = GDK_CROSSHAIR;
+}
+
+void
+set_func(GtkRadioAction *action, GtkRadioAction *current,
+ gpointer user_data)
+{
+ gint value = gtk_radio_action_get_current_value (current);
+ switch (value)
+ {
+ case 0:
+ set_arrow_func();
+ break;
+ case 1:
+ set_object_func(object_on_button_press, get_rectangle_factory);
+ break;
+ case 2:
+ set_object_func(object_on_button_press, get_circle_factory);
+ break;
+ case 3:
+ set_object_func(object_on_button_press, get_polygon_factory);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+add_shape(Object_t *obj)
+{
+ object_list_append(_shapes, obj);
+}
+
+ObjectList_t*
+get_shapes(void)
+{
+ return _shapes;
+}
+
+void
+update_shape(Object_t *obj)
+{
+ object_list_update(_shapes, obj);
+}
+
+void
+do_edit_selected_shape(void)
+{
+ object_list_edit_selected(_shapes);
+}
+
+void
+do_popup_menu(GdkEventButton *event)
+{
+ gint x = GET_REAL_COORD((gint) event->x);
+ gint y = GET_REAL_COORD((gint) event->y);
+ Object_t *obj = object_list_find(_shapes, x, y);
+ if (obj) {
+ obj->class->do_popup(obj, event);
+ } else {
+ do_main_popup_menu(event);
+ }
+}
+
+static void
+set_all_sensitivities(void)
+{
+ gint count = object_list_nr_selected(_shapes);
+ menu_shapes_selected(count);
+}
+
+static void
+main_set_title(const char *filename)
+{
+ char *title, *p;
+
+ g_strreplace(&_filename, filename);
+ p = filename ? g_filename_display_basename (filename) : (gchar *) _("<Untitled>");
+ title = g_strdup_printf("%s - Image Map", p);
+ if (filename)
+ g_free (p);
+ gtk_window_set_title(GTK_WINDOW(_dlg), title);
+ g_free(title);
+}
+
+void
+main_set_dimension(gint width, gint height)
+{
+ statusbar_set_dimension(_statusbar,
+ width / _zoom_factor, height / _zoom_factor);
+}
+
+void
+main_clear_dimension(void)
+{
+ statusbar_clear_dimension(_statusbar);
+}
+
+void
+show_url(void)
+{
+ _show_url = TRUE;
+}
+
+void
+hide_url(void)
+{
+ _show_url = FALSE;
+ statusbar_clear_status(_statusbar);
+}
+
+void
+select_shape(GtkWidget *widget, GdkEventButton *event)
+{
+ Object_t *obj;
+ gint x = GET_REAL_COORD((gint) event->x);
+ gint y = GET_REAL_COORD((gint) event->y);
+ MoveSashFunc_t sash_func;
+
+ obj = object_list_near_sash(_shapes, x, y, &sash_func);
+ if (obj) { /* Start resizing */
+ Command_t *command = move_sash_command_new(widget, obj, x, y, sash_func);
+ command_execute(command);
+ } else {
+ Command_t *command;
+
+ obj = object_list_find(_shapes, x, y);
+ if (obj) {
+ if (event->state & GDK_SHIFT_MASK) {
+ if (obj->selected)
+ command = unselect_command_new(obj);
+ else
+ command = select_command_new(obj);
+ } else { /* No Shift key pressed */
+ if (obj->selected) {
+ command = unselect_all_command_new(_shapes, obj);
+ } else {
+ Command_t *sub_command;
+
+ command = subcommand_start(NULL);
+ sub_command = unselect_all_command_new(_shapes, NULL);
+ command_add_subcommand(command, sub_command);
+ sub_command = select_command_new(obj);
+ command_add_subcommand(command, sub_command);
+ command_set_name(command, sub_command->name);
+ subcommand_end();
+ }
+ }
+ command_execute(command);
+
+ command = move_command_new(_preview, obj, x, y);
+ command_execute(command);
+ } else { /* Start selection rectangle */
+ command = select_region_command_new(widget, _shapes, x, y);
+ command_execute(command);
+ }
+ }
+}
+
+void
+edit_shape(gint x, gint y)
+{
+ Object_t *obj;
+
+ x = GET_REAL_COORD(x);
+ y = GET_REAL_COORD(y);
+
+ obj = object_list_find(_shapes, x, y);
+ if (obj) {
+ object_select(obj);
+ object_edit(obj, TRUE);
+ }
+}
+
+void
+do_zoom_in(void)
+{
+ gint factor = zoom_in();
+ menu_set_zoom_sensitivity(factor);
+}
+
+void
+do_zoom_out(void)
+{
+ gint factor = zoom_out();
+ menu_set_zoom_sensitivity(factor);
+}
+
+void
+draw_shapes(cairo_t *cr)
+{
+ object_list_draw(_shapes, cr);
+}
+
+static void
+clear_map_info(void)
+{
+ const gchar *author = g_get_real_name();
+
+ if (!*author)
+ author = g_get_user_name();
+ g_strreplace(&_map_info.image_name, _image_name);
+ g_strreplace(&_map_info.title, "map");
+ g_strreplace(&_map_info.author, author);
+ g_strreplace(&_map_info.default_url, "");
+ g_strreplace(&_map_info.description, "");
+
+ _map_info.map_format = _preferences.default_map_type;
+ _map_info.show_gray = FALSE;
+}
+
+static void
+do_data_changed_dialog(void (*continue_cb)(gpointer), gpointer param)
+{
+ GtkWidget *dialog = gtk_message_dialog_new
+ (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("Some data has been changed!"));
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ _("Do you really want to discard your changes?"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
+ continue_cb (param);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+check_if_changed(void (*func)(gpointer), gpointer param)
+{
+ if (object_list_get_changed (_shapes))
+ do_data_changed_dialog (func, param);
+ else
+ func (param);
+}
+
+static void
+close_current(void)
+{
+ selection_freeze(_selection);
+ object_list_remove_all(_shapes);
+ selection_thaw(_selection);
+ clear_map_info();
+ main_set_title(NULL);
+ set_all_sensitivities();
+ preview_redraw();
+ object_list_clear_changed(_shapes);
+ command_list_remove_all();
+}
+
+static void
+really_close(gpointer data)
+{
+ close_current();
+}
+
+void
+do_close(void)
+{
+ check_if_changed(really_close, NULL);
+}
+
+static void
+really_quit(gpointer data)
+{
+ preferences_save(&_preferences);
+ run_flag = 1;
+ gtk_widget_destroy(_dlg);
+}
+
+void
+do_quit(void)
+{
+ check_if_changed(really_quit, NULL);
+}
+
+void
+do_undo(void)
+{
+ selection_freeze(_selection);
+ last_command_undo();
+ selection_thaw(_selection);
+ preview_redraw();
+}
+
+void
+do_redo(void)
+{
+ selection_freeze(_selection);
+ last_command_redo();
+ selection_thaw(_selection);
+ preview_redraw();
+}
+
+void
+save(void)
+{
+ if (_filename)
+ save_as(_filename);
+ else
+ do_file_save_as_dialog();
+}
+
+static void
+write_cern_comment(gpointer param, OutputFunc_t output)
+{
+ output(param, "rect (4096,4096) (4096,4096) imap:#$");
+}
+
+static void
+save_as_cern(gpointer param, OutputFunc_t output)
+{
+ char *p;
+ gchar *description;
+ gchar *next_token;
+
+ write_cern_comment(param, output);
+ output(param, "-:Image map file created by GIMP Image Map plug-in\n");
+ write_cern_comment(param, output);
+ output(param, "-:GIMP Image Map plug-in by Maurits Rijk\n");
+ write_cern_comment(param, output);
+ output(param, "-:Please do not edit lines starting with \"#$\"\n");
+ write_cern_comment(param, output);
+ output(param, "VERSION:2.3\n");
+ write_cern_comment(param, output);
+ output(param, "TITLE:%s\n", _map_info.title);
+ write_cern_comment(param, output);
+ output(param, "AUTHOR:%s\n", _map_info.author);
+ write_cern_comment(param, output);
+ output(param, "FORMAT:cern\n");
+
+ description = g_strdup(_map_info.description);
+ next_token = description;
+ for (p = strtok (next_token, "\n"); p; p = strtok(NULL, "\n")) {
+ write_cern_comment(param, output);
+ output(param, "DESCRIPTION:%s\n", p);
+ }
+ g_free(description);
+
+ if (*_map_info.default_url)
+ output(param, "default %s\n", _map_info.default_url);
+ object_list_write_cern(_shapes, param, output);
+}
+
+static void
+save_as_csim(gpointer param, OutputFunc_t output)
+{
+ char *p;
+ gchar *description;
+
+ output(param, "<img src=\"%s\" width=\"%d\" height=\"%d\" border=\"0\" "
+ "usemap=\"#%s\" />\n\n", _map_info.image_name,
+ _image_width, _image_height, _map_info.title);
+ output(param, "<map name=\"%s\">\n", _map_info.title);
+ output(param,
+ "<!-- #$-:Image map file created by GIMP Image Map plug-in -->\n");
+ output(param, "<!-- #$-:GIMP Image Map plug-in by Maurits Rijk -->\n");
+ output(param,
+ "<!-- #$-:Please do not edit lines starting with \"#$\" -->\n");
+ output(param, "<!-- #$VERSION:2.3 -->\n");
+ output(param, "<!-- #$AUTHOR:%s -->\n", _map_info.author);
+
+ description = g_strdup(_map_info.description);
+ for (p = strtok(description, "\n"); p; p = strtok(NULL, "\n"))
+ output(param, "<!-- #$DESCRIPTION:%s -->\n", p);
+ g_free(description);
+
+ object_list_write_csim(_shapes, param, output);
+ if (*_map_info.default_url)
+ output(param, "<area shape=\"default\" href=\"%s\" />\n",
+ _map_info.default_url);
+ output(param, "</map>\n");
+}
+
+static void
+save_as_ncsa(gpointer param, OutputFunc_t output)
+{
+ char *p;
+ gchar *description;
+
+ output(param, "#$-:Image map file created by GIMP Image Map plug-in\n");
+ output(param, "#$-:GIMP Image Map plug-in by Maurits Rijk\n");
+ output(param, "#$-:Please do not edit lines starting with \"#$\"\n");
+ output(param, "#$VERSION:2.3\n");
+ output(param, "#$TITLE:%s\n", _map_info.title);
+ output(param, "#$AUTHOR:%s\n", _map_info.author);
+ output(param, "#$FORMAT:ncsa\n");
+
+ description = g_strdup(_map_info.description);
+ for (p = strtok(description, "\n"); p; p = strtok(NULL, "\n"))
+ output(param, "#$DESCRIPTION:%s\n", p);
+ g_free(description);
+
+ if (*_map_info.default_url)
+ output(param, "default %s\n", _map_info.default_url);
+ object_list_write_ncsa(_shapes, param, output);
+}
+
+static void save_to_file (gpointer param,
+ const char *format,
+ ...) G_GNUC_PRINTF(2,3);
+
+static void
+save_to_file(gpointer param, const char* format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf((FILE*)param, format, ap);
+ va_end(ap);
+}
+
+void
+dump_output(gpointer param, OutputFunc_t output)
+{
+ if (_map_info.map_format == NCSA)
+ save_as_ncsa(param, output);
+ else if (_map_info.map_format == CERN)
+ save_as_cern(param, output);
+ else if (_map_info.map_format == CSIM)
+ save_as_csim(param, output);
+}
+
+void
+save_as(const gchar *filename)
+{
+ FILE *out = g_fopen(filename, "w");
+ if (out) {
+ dump_output(out, save_to_file);
+ fclose(out);
+
+ statusbar_set_status(_statusbar, _("File \"%s\" saved."), filename);
+ main_set_title(filename);
+ object_list_clear_changed(_shapes);
+ } else {
+ do_file_error_dialog( _("Couldn't save file:"), filename);
+ }
+}
+
+static void
+do_image_size_changed_dialog(void)
+{
+ GtkWidget *dialog = gtk_message_dialog_new_with_markup
+ (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ _("Image size has changed."),
+ _("Resize area's?"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
+ {
+ gint per_x = _image_width * 100 / _map_info.old_image_width;
+ gint per_y = _image_height * 100 / _map_info.old_image_height;
+ object_list_resize(_shapes, per_x, per_y);
+ }
+
+ preview_redraw();
+ gtk_widget_destroy (dialog);
+}
+
+static void
+really_load(gpointer data)
+{
+ gchar *filename = (gchar*) data;
+ close_current();
+
+ selection_freeze(_selection);
+ _map_info.old_image_width = _image_width;
+ _map_info.old_image_height = _image_height;
+ if (load_csim(filename)) {
+ _map_info.map_format = CSIM;
+ if (_image_width != _map_info.old_image_width ||
+ _image_height != _map_info.old_image_height) {
+ do_image_size_changed_dialog();
+ }
+ } else if (load_ncsa(filename)) {
+ _map_info.map_format = NCSA;
+ } else if (load_cern(filename)) {
+ _map_info.map_format = CERN;
+ } else {
+ do_file_error_dialog( _("Couldn't read file:"), filename);
+ selection_thaw(_selection);
+ close_current();
+ return;
+ }
+ mru_set_first(_mru, filename);
+ menu_build_mru_items(_mru);
+
+ selection_thaw(_selection);
+ main_set_title(filename);
+ object_list_clear_changed(_shapes);
+ preview_redraw();
+}
+
+void
+load(const gchar *filename)
+{
+ static gchar *tmp_filename;
+ g_strreplace(&tmp_filename, filename);
+ check_if_changed(really_load, (gpointer) tmp_filename);
+}
+
+void
+toggle_area_list(void)
+{
+ selection_toggle_visibility(_selection);
+}
+
+static gboolean
+close_callback(GtkWidget *widget, gpointer data)
+{
+ do_quit();
+ return TRUE;
+}
+
+static gboolean
+preview_move(GtkWidget *widget, GdkEventMotion *event)
+{
+ gint x = GET_REAL_COORD((gint) event->x);
+ gint y = GET_REAL_COORD((gint) event->y);
+ static Object_t *prev_obj = NULL;
+ Object_t *obj = object_list_find(_shapes, x, y);
+
+ statusbar_set_xy(_statusbar, x, y);
+ if (obj != prev_obj) {
+ prev_obj = obj;
+ if (obj && _show_url) {
+ statusbar_set_status(_statusbar, _("URL: %s"), obj->url);
+ } else {
+ statusbar_clear_status(_statusbar);
+ }
+ }
+#ifdef _NOT_READY_YET_
+ if (!obj) {
+ if (grid_near_x(x)) {
+ preview_set_cursor(_preview, GDK_SB_H_DOUBLE_ARROW);
+ } else if (grid_near_y(y)) {
+ preview_set_cursor(_preview, GDK_SB_V_DOUBLE_ARROW);
+ } else {
+ preview_set_cursor(_preview, _cursor);
+ }
+ }
+#endif
+ return FALSE;
+}
+
+static void
+preview_enter(GtkWidget *widget, GdkEventCrossing *event)
+{
+ preview_set_cursor(_preview, _cursor);
+}
+
+static void
+preview_leave(GtkWidget *widget, GdkEventCrossing *event)
+{
+ gdk_window_set_cursor(gtk_widget_get_window (_dlg), NULL);
+ statusbar_clear_xy(_statusbar);
+}
+
+static gboolean
+button_press(GtkWidget* widget, GdkEventButton* event, gpointer data)
+{
+ if (_button_press_func)
+ return _button_press_func(widget, event, _button_press_param);
+
+ return FALSE;
+}
+
+/* A few global vars for key movement */
+
+static guint _timeout;
+static guint _keyval;
+static gint _dx, _dy;
+
+static void
+move_sash_selected_objects(gint dx, gint dy, gboolean fast)
+{
+ if (fast) {
+ dx *= 5;
+ dy *= 5;
+ }
+
+ object_list_move_sash_selected(_shapes, dx, dy);
+
+ preview_redraw ();
+}
+
+static void
+move_selected_objects(gint dx, gint dy, gboolean fast)
+{
+ if (fast) {
+ dx *= 5;
+ dy *= 5;
+ }
+ _dx += dx;
+ _dy += dy;
+
+ object_list_move_selected(_shapes, dx, dy);
+
+ preview_redraw ();
+}
+
+static gboolean
+key_timeout_cb(gpointer data)
+{
+ switch (_keyval) {
+ case GDK_KEY_Left:
+ case GDK_KEY_Right:
+ case GDK_KEY_Up:
+ case GDK_KEY_Down:
+ command_list_add(move_selected_command_new(_shapes, _dx, _dy));
+ _dx = _dy = 0;
+ break;
+ }
+ preview_redraw();
+
+ _timeout = 0;
+ return FALSE;
+}
+
+static gboolean
+key_press_cb(GtkWidget *widget, GdkEventKey *event)
+{
+ gboolean handled = FALSE;
+ gboolean shift = event->state & GDK_SHIFT_MASK;
+ gboolean ctrl = event->state & GDK_CONTROL_MASK;
+ Command_t *command;
+
+ if (_timeout)
+ g_source_remove(_timeout);
+ _timeout = 0;
+
+ switch (event->keyval) {
+ case GDK_KEY_Left:
+ if (ctrl)
+ move_sash_selected_objects(-1, 0, shift);
+ else
+ move_selected_objects(-1, 0, shift);
+ handled = TRUE;
+ break;
+ case GDK_KEY_Right:
+ if (ctrl)
+ move_sash_selected_objects(1, 0, shift);
+ else
+ move_selected_objects(1, 0, shift);
+ handled = TRUE;
+ break;
+ case GDK_KEY_Up:
+ if (ctrl)
+ move_sash_selected_objects(0, -1, shift);
+ else
+ move_selected_objects(0, -1, shift);
+ handled = TRUE;
+ break;
+ case GDK_KEY_Down:
+ if (ctrl)
+ move_sash_selected_objects(0, 1, shift);
+ else
+ move_selected_objects(0, 1, shift);
+ handled = TRUE;
+ break;
+ case GDK_KEY_Tab:
+ if (shift)
+ command = select_prev_command_new(_shapes);
+ else
+ command = select_next_command_new(_shapes);
+ command_execute(command);
+ handled = TRUE;
+ break;
+ }
+ if (handled)
+ g_signal_stop_emission_by_name(widget, "key-press-event");
+
+ return handled;
+}
+
+static gboolean
+key_release_cb(GtkWidget *widget, GdkEventKey *event)
+{
+ _keyval = event->keyval;
+ _timeout = g_timeout_add(250, key_timeout_cb, NULL);
+ return FALSE;
+}
+
+static void
+geometry_changed(Object_t *obj, gpointer data)
+{
+ preview_redraw();
+}
+
+static void
+data_changed(Object_t *obj, gpointer data)
+{
+ preview_redraw();
+ set_all_sensitivities();
+}
+
+static void
+data_selected(Object_t *obj, gpointer data)
+{
+ set_all_sensitivities();
+}
+
+void
+imap_help (void)
+{
+ gimp_standard_help_func ("plug-in-imagemap", NULL);
+}
+
+void
+do_cut (void)
+{
+ command_execute (cut_command_new (_shapes));
+}
+
+void
+do_copy (void)
+{
+ command_execute (copy_command_new (_shapes));
+}
+
+void
+do_paste (void)
+{
+ command_execute (paste_command_new (_shapes));
+}
+
+void
+do_select_all(void)
+{
+ command_execute (select_all_command_new (_shapes));
+}
+
+void
+do_deselect_all(void)
+{
+ command_execute (unselect_all_command_new (_shapes, NULL));
+}
+
+void
+do_clear(void)
+{
+ command_execute (clear_command_new(_shapes));
+}
+
+void
+do_move_up(void)
+{
+ /* Fix me!
+ Command_t *command = object_up_command_new(_current_obj->list,
+ _current_obj);
+ command_execute(command);
+ */
+}
+
+void
+do_move_down(void)
+{
+ /* Fix me!
+ Command_t *command = object_down_command_new(_current_obj->list,
+ _current_obj);
+ command_execute(command);
+ */
+}
+
+void
+do_move_to_front(void)
+{
+ command_execute(move_to_front_command_new(_shapes));
+}
+
+void
+do_send_to_back(void)
+{
+ command_execute(send_to_back_command_new(_shapes));
+}
+
+void
+do_use_gimp_guides_dialog(void)
+{
+ command_execute (gimp_guides_command_new (_shapes, _drawable_id));
+}
+
+void
+do_create_guides_dialog(void)
+{
+ command_execute (guides_command_new (_shapes));
+}
+
+static Command_t*
+factory_move_up(void)
+{
+ return move_up_command_new(_shapes);
+}
+
+static Command_t*
+factory_move_down(void)
+{
+ return move_down_command_new(_shapes);
+}
+
+static gint
+dialog(gint32 drawable_id)
+{
+ GtkWidget *dlg;
+ GtkWidget *hbox;
+ GtkWidget *main_vbox;
+ GtkWidget *tools;
+
+ gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+ set_arrow_func ();
+
+ _shapes = make_object_list();
+
+ _dlg = dlg = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE);
+
+ main_set_title(NULL);
+ gimp_help_connect (dlg, gimp_standard_help_func, PLUG_IN_PROC, NULL);
+
+ gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
+
+ gimp_window_set_transient (GTK_WINDOW (dlg));
+
+ g_signal_connect (dlg, "delete-event",
+ G_CALLBACK (close_callback), NULL);
+ g_signal_connect (dlg, "key-press-event",
+ G_CALLBACK (key_press_cb), NULL);
+ g_signal_connect (dlg, "key-release-event",
+ G_CALLBACK (key_release_cb), NULL);
+
+ g_signal_connect (dlg, "destroy",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add (GTK_CONTAINER (dlg), main_vbox);
+ gtk_widget_show (main_vbox);
+
+ init_stock_icons();
+
+ /* Create menu */
+ make_menu(main_vbox, dlg);
+
+ /* Create toolbar */
+ make_toolbar(main_vbox, dlg);
+
+ /* Dialog area */
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_box_pack_start (GTK_BOX (main_vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show(hbox);
+
+ tools = make_tools(dlg);
+ /* selection_set_edit_command(tools, factory_edit); */
+ gtk_box_pack_start(GTK_BOX(hbox), tools, FALSE, FALSE, 0);
+
+ _preview = make_preview(drawable_id);
+
+ g_signal_connect(_preview->preview, "motion-notify-event",
+ G_CALLBACK(preview_move), NULL);
+ g_signal_connect(_preview->preview, "enter-notify-event",
+ G_CALLBACK(preview_enter), NULL);
+ g_signal_connect(_preview->preview, "leave-notify-event",
+ G_CALLBACK(preview_leave), NULL);
+ g_signal_connect(_preview->preview, "button-press-event",
+ G_CALLBACK(button_press), NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), _preview->window, TRUE, TRUE, 0);
+
+ object_list_add_geometry_cb(_shapes, geometry_changed, NULL);
+ object_list_add_update_cb(_shapes, data_changed, NULL);
+ object_list_add_add_cb(_shapes, data_changed, NULL);
+ object_list_add_remove_cb(_shapes, data_changed, NULL);
+ object_list_add_move_cb(_shapes, data_changed, NULL);
+ object_list_add_select_cb(_shapes, data_selected, NULL);
+
+ /* Selection */
+ _selection = make_selection(_shapes);
+ selection_set_move_up_command(_selection, factory_move_up);
+ selection_set_move_down_command(_selection, factory_move_down);
+ gtk_box_pack_start(GTK_BOX(hbox), _selection->container, FALSE, FALSE, 0);
+
+ _statusbar = make_statusbar(main_vbox, dlg);
+ statusbar_set_zoom(_statusbar, 1);
+
+ gtk_widget_show(dlg);
+
+ _mru = mru_create();
+ init_preferences();
+
+ clear_map_info();
+
+ if (!mru_empty(_mru))
+ menu_build_mru_items(_mru);
+
+ gtk_main();
+
+ return run_flag;
+}
diff --git a/plug-ins/imagemap/imap_main.h b/plug-ins/imagemap/imap_main.h
new file mode 100644
index 0000000..b22327d
--- /dev/null
+++ b/plug-ins/imagemap/imap_main.h
@@ -0,0 +1,125 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_MAIN_H
+#define _IMAP_MAIN_H
+
+#include "imap_mru.h"
+#include "imap_object.h"
+#include "imap_preferences.h"
+#include "imap_preview.h"
+
+#define PLUG_IN_PROC "plug-in-imagemap"
+#define PLUG_IN_BINARY "imagemap"
+#define PLUG_IN_ROLE "gimp-imagemap"
+
+typedef enum {NCSA, CERN, CSIM} MapFormat_t;
+
+typedef struct {
+ MapFormat_t map_format;
+ gchar *image_name;
+ gchar *title;
+ gchar *author;
+ gchar *default_url;
+ gchar *description;
+ gint old_image_width;
+ gint old_image_height;
+ gboolean color; /* Color (TRUE) or Gray (FALSE) */
+ gboolean show_gray;
+} MapInfo_t;
+
+void main_set_dimension(gint width, gint height);
+void main_clear_dimension(void);
+void load(const gchar *filename);
+void save_as(const gchar *filename);
+void dump_output(gpointer param, OutputFunc_t output);
+GtkWidget *get_dialog(void);
+MRU_t *get_mru(void);
+MapInfo_t *get_map_info(void);
+PreferencesData_t *get_preferences(void);
+
+gint get_image_width(void);
+gint get_image_height(void);
+
+void set_busy_cursor(void);
+void remove_busy_cursor(void);
+
+void main_toolbar_set_grid(gboolean active);
+
+void set_zoom(gint zoom_factor);
+gint get_real_coord(gint coord);
+void draw_line(cairo_t *cr, gint x1, gint y1, gint x2,
+ gint y2);
+void draw_rectangle(cairo_t *cr, gboolean filled, gint x, gint y,
+ gint width, gint height);
+void draw_circle(cairo_t *cr, gint x, gint y,
+ gint r);
+void draw_polygon(cairo_t *cr, GList *list);
+
+const char *get_filename(void);
+
+ObjectList_t *get_shapes(void);
+void add_shape(Object_t *obj);
+void update_shape(Object_t *obj);
+void select_shape(GtkWidget *widget, GdkEventButton *event);
+void edit_shape(gint x, gint y);
+
+void do_popup_menu(GdkEventButton *event);
+void draw_shapes(cairo_t *cr);
+
+void show_url(void);
+void hide_url(void);
+
+void set_preview_color (GtkRadioAction *action,
+ GtkRadioAction *current,
+ gpointer user_data);
+void set_zoom_factor (GtkRadioAction *action,
+ GtkRadioAction *current,
+ gpointer user_data);
+void set_func (GtkRadioAction *action,
+ GtkRadioAction *current,
+ gpointer user_data);
+void do_edit_selected_shape (void);
+void do_zoom_in (void);
+void do_zoom_out (void);
+void do_close (void);
+void do_quit (void);
+void do_undo (void);
+void do_redo (void);
+void do_cut (void);
+void do_copy (void);
+void do_paste (void);
+void do_select_all (void);
+void do_deselect_all (void);
+void do_clear (void);
+void do_move_up (void);
+void do_move_down (void);
+void do_move_to_front (void);
+void do_send_to_back (void);
+void do_use_gimp_guides_dialog (void);
+void do_create_guides_dialog (void);
+void save (void);
+void imap_help (void);
+void toggle_area_list (void);
+const gchar * get_image_name (void);
+
+#endif /* _IMAP_MAIN_H */
diff --git a/plug-ins/imagemap/imap_menu.c b/plug-ins/imagemap/imap_menu.c
new file mode 100644
index 0000000..8e1d0d1
--- /dev/null
+++ b/plug-ins/imagemap/imap_menu.c
@@ -0,0 +1,551 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2006 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 "libgimp/gimpui.h"
+
+#include "imap_about.h"
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_grid.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_menu_funcs.h"
+#include "imap_polygon.h"
+#include "imap_preferences.h"
+#include "imap_rectangle.h"
+#include "imap_settings.h"
+#include "imap_stock.h"
+#include "imap_source.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static Menu_t _menu;
+static GtkUIManager *ui_manager;
+
+GtkWidget*
+menu_get_widget(const gchar *path)
+{
+ return gtk_ui_manager_get_widget (ui_manager, path);
+}
+
+static void
+set_sensitive (const gchar *path, gboolean sensitive)
+{
+ GtkAction *action = gtk_ui_manager_get_action (ui_manager, path);
+ g_object_set (action, "sensitive", sensitive, NULL);
+}
+
+static void
+menu_mru(GtkWidget *widget, gpointer data)
+{
+ MRU_t *mru = get_mru();
+ char *filename = (char*) data;
+
+ if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+ load(filename);
+ } else {
+ do_file_error_dialog(_("Error opening file"), filename);
+ mru_remove(mru, filename);
+ menu_build_mru_items(mru);
+ }
+}
+
+void
+menu_set_zoom_sensitivity(gint factor)
+{
+ set_sensitive ("/MainMenu/ViewMenu/ZoomIn", factor < 8);
+ set_sensitive ("/MainMenu/ViewMenu/ZoomOut", factor > 1);
+}
+
+void
+menu_set_zoom(gint factor)
+{
+ menu_set_zoom_sensitivity (factor);
+}
+
+void
+menu_shapes_selected(gint count)
+{
+ gboolean sensitive = (count > 0);
+
+ set_sensitive ("/MainMenu/EditMenu/Cut", sensitive);
+ set_sensitive ("/MainMenu/EditMenu/Copy", sensitive);
+ set_sensitive ("/MainMenu/EditMenu/Clear", sensitive);
+ set_sensitive ("/MainMenu/EditMenu/EditAreaInfo", sensitive);
+ set_sensitive ("/MainMenu/EditMenu/DeselectAll", sensitive);
+}
+
+static void
+command_list_changed(Command_t *command, gpointer data)
+{
+ GtkAction *action;
+ gchar *label;
+
+ action = gtk_ui_manager_get_action (ui_manager, "/MainMenu/EditMenu/Undo");
+
+ label = g_strdup_printf (_("_Undo %s"),
+ command && command->name ? command->name : "");
+
+ g_object_set (action,
+ "label", label,
+ "sensitive", command != NULL,
+ NULL);
+ g_free (label);
+
+ command = command_list_get_redo_command();
+
+ action = gtk_ui_manager_get_action (ui_manager, "/MainMenu/EditMenu/Redo");
+
+ label = g_strdup_printf (_("_Redo %s"),
+ command && command->name ? command->name : "");
+ g_object_set (action,
+ "label", label,
+ "sensitive", command != NULL,
+ NULL);
+ g_free (label);
+}
+
+static void
+paste_buffer_added(Object_t *obj, gpointer data)
+{
+ set_sensitive("/MainMenu/EditMenu/Paste", TRUE);
+}
+
+static void
+paste_buffer_removed(Object_t *obj, gpointer data)
+{
+ set_sensitive("/MainMenu/EditMenu/Paste", FALSE);
+}
+
+/* Normal items */
+static const GtkActionEntry entries[] =
+{
+ { "FileMenu", NULL,
+ N_("_File") },
+ { "Open", GIMP_ICON_DOCUMENT_OPEN,
+ N_("_Open..."), NULL, N_("Open"),
+ do_file_open_dialog},
+ { "Save", GIMP_ICON_DOCUMENT_SAVE,
+ N_("_Save..."), NULL, N_("Save"),
+ save},
+ { "SaveAs", GIMP_ICON_DOCUMENT_SAVE_AS,
+ N_("Save _As..."), "<shift><control>S", NULL,
+ do_file_save_as_dialog},
+ { "Close", GIMP_ICON_CLOSE, N_("_Close"), "<primary>w", NULL, do_close},
+ { "Quit", GIMP_ICON_APPLICATION_EXIT,
+ N_("_Quit"), "<primary>q", NULL, do_quit},
+
+ { "EditMenu", NULL, N_("_Edit") },
+ { "Undo", GIMP_ICON_EDIT_UNDO,
+ N_("_Undo"), NULL, N_("Undo"), do_undo},
+ { "Redo", GIMP_ICON_EDIT_REDO,
+ N_("_Redo"), NULL, N_("Redo"), do_redo},
+ { "Cut", GIMP_ICON_EDIT_CUT,
+ N_("Cu_t"), "<primary>x", N_("Cut"), do_cut},
+ { "Copy", GIMP_ICON_EDIT_COPY,
+ N_("_Copy"), "<primary>c", N_("Copy"), do_copy},
+ { "Paste", GIMP_ICON_EDIT_PASTE,
+ N_("_Paste"), "<primary>v", N_("Paste"), do_paste},
+ { "Clear", GIMP_ICON_EDIT_DELETE,
+ N_("_Delete"), NULL, N_("Delete"), do_clear},
+ { "SelectAll", NULL,
+ N_("Select _All"), "<primary>A", NULL, do_select_all},
+ { "DeselectAll", NULL,
+ N_("D_eselect All"), "<shift><primary>A", NULL,
+ do_deselect_all},
+ { "EditAreaInfo", GIMP_ICON_EDIT
+ , N_("Edit Area _Info..."), NULL,
+ N_("Edit selected area info"), do_edit_selected_shape},
+ { "Preferences", GIMP_ICON_PREFERENCES_SYSTEM,
+ N_("_Preferences"), NULL, N_("Preferences"),
+ do_preferences_dialog},
+ { "MoveToFront", IMAP_STOCK_TO_FRONT, "", NULL, N_("Move Area to Front"),
+ do_move_to_front},
+ { "SendToBack", IMAP_STOCK_TO_BACK, "", NULL, N_("Move Area to Bottom"),
+ do_send_to_back},
+ { "DeleteArea", NULL, N_("Delete Area"), NULL, NULL, NULL},
+ { "MoveUp", GIMP_ICON_GO_UP, N_("Move Up"), NULL, NULL, NULL},
+ { "MoveDown", GIMP_ICON_GO_DOWN, N_("Move Down"), NULL, NULL, NULL},
+
+ { "InsertPoint", NULL, N_("Insert Point"), NULL, NULL, polygon_insert_point},
+ { "DeletePoint", NULL, N_("Delete Point"), NULL, NULL, polygon_delete_point},
+
+ { "ViewMenu", NULL, N_("_View") },
+ { "Source", NULL, N_("Source..."), NULL, NULL, do_source_dialog},
+ { "ZoomIn", GIMP_ICON_ZOOM_IN, N_("Zoom _In"), "plus", N_("Zoom in"), do_zoom_in},
+ { "ZoomOut", GIMP_ICON_ZOOM_OUT, N_("Zoom _Out"), "minus", N_("Zoom out"), do_zoom_out},
+ { "ZoomToMenu", NULL, N_("_Zoom To") },
+
+ { "MappingMenu", NULL, N_("_Mapping") },
+ { "EditMapInfo", GIMP_ICON_DIALOG_INFORMATION, N_("Edit Map Info..."), NULL,
+ N_("Edit Map Info"), do_settings_dialog},
+
+ { "ToolsMenu", NULL, N_("_Tools") },
+ { "GridSettings", NULL, N_("Grid Settings..."), NULL, NULL,
+ do_grid_settings_dialog},
+ { "UseGimpGuides", NULL, N_("Use GIMP Guides..."), NULL, NULL,
+ do_use_gimp_guides_dialog},
+ { "CreateGuides", NULL, N_("Create Guides..."), NULL, NULL,
+ do_create_guides_dialog},
+
+ { "HelpMenu", NULL, N_("_Help") },
+ { "Contents", GIMP_ICON_HELP, N_("_Contents"), NULL, NULL, imap_help},
+ { "About", GIMP_ICON_HELP_ABOUT, N_("_About"), NULL, NULL, do_about_dialog},
+
+ { "ZoomMenu", NULL, N_("_Zoom") },
+};
+
+/* Toggle items */
+static const GtkToggleActionEntry toggle_entries[] = {
+ { "AreaList", NULL, N_("Area List"), NULL, NULL, NULL, TRUE },
+ { "Grid", GIMP_ICON_GRID, N_("_Grid"), NULL, N_("Grid"), toggle_grid, FALSE }
+};
+
+static const GtkRadioActionEntry color_entries[] = {
+ { "Color", NULL, N_("Color"), NULL, NULL, 0},
+ { "Gray", NULL, N_("Gray"), NULL, NULL, 1},
+};
+
+static const GtkRadioActionEntry mapping_entries[] = {
+ { "Arrow", GIMP_ICON_CURSOR, N_("Arrow"), NULL,
+ N_("Select existing area"), 0},
+ { "Rectangle", IMAP_STOCK_RECTANGLE, N_("Rectangle"), NULL,
+ N_("Define Rectangle area"), 1},
+ { "Circle", IMAP_STOCK_CIRCLE, N_("Circle"), NULL,
+ N_("Define Circle/Oval area"), 2},
+ { "Polygon", IMAP_STOCK_POLYGON, N_("Polygon"), NULL,
+ N_("Define Polygon area"), 3},
+};
+
+static const GtkRadioActionEntry zoom_entries[] = {
+ { "Zoom1:1", NULL, "1:1", NULL, NULL, 0},
+ { "Zoom1:2", NULL, "1:2", NULL, NULL, 1},
+ { "Zoom1:3", NULL, "1:3", NULL, NULL, 2},
+ { "Zoom1:4", NULL, "1:4", NULL, NULL, 3},
+ { "Zoom1:5", NULL, "1:5", NULL, NULL, 4},
+ { "Zoom1:6", NULL, "1:6", NULL, NULL, 5},
+ { "Zoom1:7", NULL, "1:7", NULL, NULL, 6},
+ { "Zoom1:8", NULL, "1:8", NULL, NULL, 7},
+};
+
+static const gchar ui_description[] =
+"<ui>"
+" <menubar name='MainMenu'>"
+" <menu action='FileMenu'>"
+" <menuitem action='Open'/>"
+" <menuitem action='Save'/>"
+" <menuitem action='SaveAs'/>"
+" <separator/>"
+" <menuitem action='Close'/>"
+" <menuitem action='Quit'/>"
+" </menu>"
+" <menu action='EditMenu'>"
+" <menuitem action='Undo'/>"
+" <menuitem action='Redo'/>"
+" <menuitem action='Cut'/>"
+" <menuitem action='Copy'/>"
+" <menuitem action='Paste'/>"
+" <menuitem action='Clear'/>"
+" <separator/>"
+" <menuitem action='SelectAll'/>"
+" <menuitem action='DeselectAll'/>"
+" <separator/>"
+" <menuitem action='EditAreaInfo'/>"
+" <separator/>"
+" <menuitem action='Preferences'/>"
+" </menu>"
+" <menu action='ViewMenu'>"
+" <menuitem action='AreaList'/>"
+" <menuitem action='Source'/>"
+" <separator/>"
+" <menuitem action='Color'/>"
+" <menuitem action='Gray'/>"
+" <separator/>"
+" <menuitem action='ZoomIn'/>"
+" <menuitem action='ZoomOut'/>"
+" <menu action='ZoomToMenu'>"
+" <menuitem action='Zoom1:1'/>"
+" <menuitem action='Zoom1:2'/>"
+" <menuitem action='Zoom1:3'/>"
+" <menuitem action='Zoom1:4'/>"
+" <menuitem action='Zoom1:5'/>"
+" <menuitem action='Zoom1:6'/>"
+" <menuitem action='Zoom1:7'/>"
+" <menuitem action='Zoom1:8'/>"
+" </menu>"
+" </menu>"
+" <menu action='MappingMenu'>"
+" <menuitem action='Arrow'/>"
+" <menuitem action='Rectangle'/>"
+" <menuitem action='Circle'/>"
+" <menuitem action='Polygon'/>"
+" <separator/>"
+" <menuitem action='EditMapInfo'/>"
+" </menu>"
+" <menu action='ToolsMenu'>"
+" <menuitem action='Grid'/>"
+" <menuitem action='GridSettings'/>"
+" <separator/>"
+" <menuitem action='UseGimpGuides'/>"
+" <menuitem action='CreateGuides'/>"
+" </menu>"
+" <menu action='HelpMenu'>"
+" <menuitem action='Contents'/>"
+" <menuitem action='About'/>"
+" </menu>"
+" </menubar>"
+""
+" <popup name='PopupMenu'>"
+" <menuitem action='EditMapInfo'/>"
+" <menu action='ToolsMenu'>"
+" <menuitem action='Arrow'/>"
+" <menuitem action='Rectangle'/>"
+" <menuitem action='Circle'/>"
+" <menuitem action='Polygon'/>"
+" </menu>"
+" <menu action='ZoomMenu'>"
+" <menuitem action='ZoomIn'/>"
+" <menuitem action='ZoomOut'/>"
+" </menu>"
+" <menuitem action='Grid'/>"
+" <menuitem action='GridSettings'/>"
+" <menuitem action='CreateGuides'/>"
+" <menuitem action='Paste'/>"
+" </popup>"
+""
+" <popup name='ObjectPopupMenu'>"
+" <menuitem action='EditAreaInfo'/>"
+" <menuitem action='DeleteArea'/>"
+" <menuitem action='MoveUp'/>"
+" <menuitem action='MoveDown'/>"
+" <menuitem action='Cut'/>"
+" <menuitem action='Copy'/>"
+" </popup>"
+""
+" <popup name='PolygonPopupMenu'>"
+" <menuitem action='InsertPoint'/>"
+" <menuitem action='DeletePoint'/>"
+" <menuitem action='EditAreaInfo'/>"
+" <menuitem action='DeleteArea'/>"
+" <menuitem action='MoveUp'/>"
+" <menuitem action='MoveDown'/>"
+" <menuitem action='Cut'/>"
+" <menuitem action='Copy'/>"
+" </popup>"
+""
+" <toolbar name='Toolbar'>"
+" <toolitem action='Open'/>"
+" <toolitem action='Save'/>"
+" <separator/>"
+" <toolitem action='Preferences'/>"
+" <separator/>"
+" <toolitem action='Undo'/>"
+" <toolitem action='Redo'/>"
+" <separator/>"
+" <toolitem action='Cut'/>"
+" <toolitem action='Copy'/>"
+" <toolitem action='Paste'/>"
+" <separator/>"
+" <toolitem action='ZoomIn'/>"
+" <toolitem action='ZoomOut'/>"
+" <separator/>"
+" <toolitem action='EditMapInfo'/>"
+" <separator/>"
+" <toolitem action='MoveToFront'/>"
+" <toolitem action='SendToBack'/>"
+" <separator/>"
+" <toolitem action='Grid'/>"
+" </toolbar>"
+""
+" <toolbar name='Tools'>"
+" <toolitem action='Arrow'/>"
+" <toolitem action='Rectangle'/>"
+" <toolitem action='Circle'/>"
+" <toolitem action='Polygon'/>"
+" <separator/>"
+" <toolitem action='EditAreaInfo'/>"
+" </toolbar>"
+""
+" <toolbar name='Selection'>"
+" <toolitem action='MoveUp'/>"
+" <toolitem action='MoveDown'/>"
+" <toolitem action='EditAreaInfo'/>"
+" <toolitem action='Clear'/>"
+" </toolbar>"
+"</ui>";
+
+Menu_t*
+make_menu(GtkWidget *main_vbox, GtkWidget *window)
+{
+ GtkWidget *menubar;
+ GtkActionGroup *action_group;
+ GtkAccelGroup *accel_group;
+ GError *error;
+
+ action_group = gtk_action_group_new ("MenuActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+
+ gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries),
+ window);
+ gtk_action_group_add_toggle_actions (action_group, toggle_entries,
+ G_N_ELEMENTS (toggle_entries), window);
+
+ gtk_action_group_add_radio_actions (action_group, color_entries,
+ G_N_ELEMENTS (color_entries), 0,
+ G_CALLBACK (set_preview_color), NULL);
+ gtk_action_group_add_radio_actions (action_group, zoom_entries,
+ G_N_ELEMENTS (zoom_entries), 0,
+ G_CALLBACK (set_zoom_factor), NULL);
+ gtk_action_group_add_radio_actions (action_group, mapping_entries,
+ G_N_ELEMENTS (mapping_entries), 0,
+ G_CALLBACK (set_func), window);
+
+ ui_manager = gtk_ui_manager_new ();
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+
+ accel_group = gtk_ui_manager_get_accel_group (ui_manager);
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+ error = NULL;
+ if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1,
+ &error))
+ {
+ g_warning ("building menus failed: %s", error->message);
+ g_error_free (error);
+ /* exit (EXIT_FAILURE); */
+ }
+
+ menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
+ gtk_widget_show (menubar);
+ gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, FALSE, 0);
+
+ paste_buffer_add_add_cb(paste_buffer_added, NULL);
+ paste_buffer_add_remove_cb(paste_buffer_removed, NULL);
+
+ set_sensitive ("/MainMenu/EditMenu/Paste", FALSE);
+ menu_shapes_selected (0);
+
+ menu_set_zoom_sensitivity (1);
+
+ command_list_add_update_cb (command_list_changed, NULL);
+
+ command_list_changed (NULL, NULL);
+
+ return &_menu;
+}
+
+void
+menu_build_mru_items(MRU_t *mru)
+{
+ GList *p;
+ gint position = 0;
+ int i;
+
+ return;
+
+ if (_menu.nr_off_mru_items) {
+ GList *children;
+
+ children = gtk_container_get_children(GTK_CONTAINER(_menu.open_recent));
+ p = g_list_nth(children, position);
+ for (i = 0; i < _menu.nr_off_mru_items; i++, p = p->next) {
+ gtk_widget_destroy((GtkWidget*) p->data);
+ }
+ g_list_free(children);
+ }
+
+ i = 0;
+ for (p = mru->list; p; p = p->next, i++) {
+ GtkWidget *item = insert_item_with_label(_menu.open_recent, position++,
+ (gchar*) p->data,
+ menu_mru, p->data);
+ if (i < 9) {
+ guchar accelerator_key = '1' + i;
+ add_accelerator(item, accelerator_key, GDK_CONTROL_MASK);
+ }
+ }
+ _menu.nr_off_mru_items = i;
+}
+
+void
+do_main_popup_menu(GdkEventButton *event)
+{
+ GtkWidget *popup = gtk_ui_manager_get_widget (ui_manager, "/PopupMenu");
+ gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+}
+
+void
+menu_check_grid(gboolean check)
+{
+ GtkAction *action = gtk_ui_manager_get_action (ui_manager,
+ "/MainMenu/ToolsMenu/Grid");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), check);
+}
+
+GtkWidget*
+make_toolbar(GtkWidget *main_vbox, GtkWidget *window)
+{
+ GtkWidget *toolbar;
+
+ toolbar = gtk_ui_manager_get_widget (ui_manager, "/Toolbar");
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+ gtk_container_set_border_width (GTK_CONTAINER (toolbar), 0);
+ gtk_box_pack_start (GTK_BOX (main_vbox), toolbar, FALSE, FALSE, 0);
+ gtk_widget_show (toolbar);
+
+ return toolbar;
+}
+
+GtkWidget*
+make_tools(GtkWidget *window)
+{
+ GtkWidget *toolbar;
+
+ toolbar = gtk_ui_manager_get_widget (ui_manager, "/Tools");
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (toolbar),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+ gtk_container_set_border_width (GTK_CONTAINER (toolbar), 0);
+ gtk_widget_show (toolbar);
+
+ return toolbar;
+}
+
+GtkWidget*
+make_selection_toolbar(void)
+{
+ GtkWidget *toolbar;
+
+ toolbar = gtk_ui_manager_get_widget (ui_manager, "/Selection");
+
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (toolbar),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_container_set_border_width (GTK_CONTAINER (toolbar), 0);
+
+ gtk_widget_show (toolbar);
+ return toolbar;
+}
diff --git a/plug-ins/imagemap/imap_menu.h b/plug-ins/imagemap/imap_menu.h
new file mode 100644
index 0000000..e34743f
--- /dev/null
+++ b/plug-ins/imagemap/imap_menu.h
@@ -0,0 +1,65 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_MENU_H
+#define _IMAP_MENU_H
+
+#include "imap_command.h"
+#include "imap_mru.h"
+
+typedef struct {
+ GtkWidget *file_menu;
+ GtkWidget *edit_menu;
+ GtkWidget *open_recent;
+ GtkWidget *undo;
+ GtkWidget *redo;
+ GtkWidget *arrow;
+ GtkWidget *fuzzy_select;
+ GtkWidget *rectangle;
+ GtkWidget *circle;
+ GtkWidget *polygon;
+ GtkWidget *grid;
+ GtkWidget *gray;
+ GtkWidget *color;
+ GtkWidget *zoom[8];
+ GtkWidget *zoom_in;
+ GtkWidget *zoom_out;
+
+ gint nr_off_mru_items;
+} Menu_t;
+
+GtkWidget *menu_get_widget(const gchar *path);
+Menu_t *make_menu(GtkWidget *main_vbox, GtkWidget *window);
+void menu_build_mru_items(MRU_t *mru);
+void menu_set_zoom_sensitivity(gint factor);
+
+void menu_set_zoom(gint factor);
+void menu_check_grid(gboolean check);
+void menu_shapes_selected(gint count);
+
+void do_main_popup_menu(GdkEventButton *event);
+
+GtkWidget *make_toolbar(GtkWidget *main_vbox, GtkWidget *window);
+GtkWidget *make_tools(GtkWidget *window);
+GtkWidget *make_selection_toolbar(void);
+
+#endif /* _IMAP_MENU_H */
diff --git a/plug-ins/imagemap/imap_menu_funcs.c b/plug-ins/imagemap/imap_menu_funcs.c
new file mode 100644
index 0000000..264a6cb
--- /dev/null
+++ b/plug-ins/imagemap/imap_menu_funcs.c
@@ -0,0 +1,58 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_command.h"
+#include "imap_menu_funcs.h"
+
+static GtkAccelGroup *accelerator_group;
+
+void
+init_accel_group(GtkWidget *window)
+{
+ accelerator_group = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(window), accelerator_group);
+}
+
+void
+add_accelerator(GtkWidget *widget, guint accelerator_key,
+ guint8 accelerator_mods)
+{
+ gtk_widget_add_accelerator(widget, "activate", accelerator_group,
+ accelerator_key, accelerator_mods,
+ GTK_ACCEL_VISIBLE);
+}
+
+GtkWidget*
+insert_item_with_label(GtkWidget *parent, gint position, gchar *label,
+ MenuCallback activate, gpointer data)
+{
+ GtkWidget *item = gtk_image_menu_item_new_with_mnemonic(label);
+ gtk_menu_shell_insert(GTK_MENU_SHELL(parent), item, position);
+ g_signal_connect(item, "activate", G_CALLBACK(activate), data);
+ gtk_widget_show(item);
+
+ return item;
+}
diff --git a/plug-ins/imagemap/imap_menu_funcs.h b/plug-ins/imagemap/imap_menu_funcs.h
new file mode 100644
index 0000000..8c2b86f
--- /dev/null
+++ b/plug-ins/imagemap/imap_menu_funcs.h
@@ -0,0 +1,39 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_MENU_FUNCS_H
+#define _IMAP_MENU_FUNCS_H
+
+typedef void (*MenuCallback)(GtkWidget *widget, gpointer data);
+
+void init_accel_group(GtkWidget *window);
+GtkWidget *insert_item_with_label(GtkWidget *parent, gint position,
+ gchar *label, MenuCallback activate,
+ gpointer data);
+
+void menu_command(GtkWidget *widget, gpointer data);
+
+void add_accelerator(GtkWidget *widget, guint accelerator_key,
+ guint8 accelerator_mods);
+
+
+#endif /* _IMAP_MENU_FUNCS_H */
diff --git a/plug-ins/imagemap/imap_misc.c b/plug-ins/imagemap/imap_misc.c
new file mode 100644
index 0000000..4a6b760
--- /dev/null
+++ b/plug-ins/imagemap/imap_misc.c
@@ -0,0 +1,52 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_main.h"
+#include "imap_misc.h"
+
+#define SASH_SIZE 8
+
+static gint _sash_size = SASH_SIZE;
+
+void
+set_sash_size(gboolean double_size)
+{
+ _sash_size = (double_size) ? 2 * SASH_SIZE : SASH_SIZE;
+}
+
+void
+draw_sash(cairo_t *cr, gint x, gint y)
+{
+ draw_rectangle(cr, TRUE, x - _sash_size / 2, y - _sash_size / 2,
+ _sash_size, _sash_size);
+}
+
+gboolean
+near_sash(gint sash_x, gint sash_y, gint x, gint y)
+{
+ return x >= sash_x - _sash_size / 2 && x <= sash_x + _sash_size / 2 &&
+ y >= sash_y - _sash_size / 2 && y <= sash_y + _sash_size / 2;
+}
diff --git a/plug-ins/imagemap/imap_misc.h b/plug-ins/imagemap/imap_misc.h
new file mode 100644
index 0000000..f8a047d
--- /dev/null
+++ b/plug-ins/imagemap/imap_misc.h
@@ -0,0 +1,31 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_MISC_H
+#define _IMAP_MISC_H
+
+void set_sash_size(gboolean double_size);
+void draw_sash(cairo_t *cr, gint x, gint y);
+gboolean near_sash(gint sash_x, gint sash_y, gint x, gint y);
+
+#endif /* _IMAP_MISC_H */
+
diff --git a/plug-ins/imagemap/imap_mru.c b/plug-ins/imagemap/imap_mru.c
new file mode 100644
index 0000000..1afb0a5
--- /dev/null
+++ b/plug-ins/imagemap/imap_mru.c
@@ -0,0 +1,105 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_mru.h"
+
+MRU_t*
+mru_create(void)
+{
+ MRU_t *mru = g_new(MRU_t, 1);
+ mru->list = NULL;
+ mru->max_size = DEFAULT_MRU_SIZE;
+ return mru;
+}
+
+void
+mru_destruct (MRU_t *mru)
+{
+ g_list_free_full (mru->list, (GDestroyNotify) g_free);
+ g_free (mru);
+}
+
+static void
+mru_remove_link(MRU_t *mru, GList *link)
+{
+ if (link)
+ {
+ g_free(link->data);
+ mru->list = g_list_remove_link(mru->list, link);
+ }
+}
+
+static GList*
+mru_find_link(MRU_t *mru, const gchar *filename)
+{
+ return g_list_find_custom(mru->list, (gpointer) filename,
+ (GCompareFunc) strcmp);
+}
+
+void
+mru_add(MRU_t *mru, const gchar *filename)
+{
+ if (g_list_length(mru->list) == mru->max_size)
+ mru_remove_link(mru, g_list_last(mru->list));
+ mru->list = g_list_prepend(mru->list, g_strdup(filename));
+}
+
+void
+mru_remove(MRU_t *mru, const gchar *filename)
+{
+ mru_remove_link(mru, mru_find_link(mru, filename));
+}
+
+void
+mru_set_first(MRU_t *mru, const gchar *filename)
+{
+ GList *link = mru_find_link(mru, filename);
+ if (link)
+ mru->list = g_list_prepend(g_list_remove_link(mru->list, link),
+ link->data);
+ else
+ mru_add(mru, filename);
+}
+
+void
+mru_set_size(MRU_t *mru, gint size)
+{
+ gint diff;
+
+ for (diff = g_list_length(mru->list) - size; diff > 0; diff--)
+ mru_remove_link(mru, g_list_last(mru->list));
+ mru->max_size = size;
+}
+
+void
+mru_write(MRU_t *mru, FILE *out)
+{
+ GList *p;
+ for (p = mru->list; p; p = p->next)
+ fprintf(out, "(mru-entry %s)\n", (gchar*) p->data);
+}
diff --git a/plug-ins/imagemap/imap_mru.h b/plug-ins/imagemap/imap_mru.h
new file mode 100644
index 0000000..6d2d954
--- /dev/null
+++ b/plug-ins/imagemap/imap_mru.h
@@ -0,0 +1,45 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_MRU_H
+#define _IMAP_MRU_H
+
+#include <stdio.h>
+
+#define DEFAULT_MRU_SIZE 4
+
+typedef struct {
+ GList *list;
+ gint max_size;
+} MRU_t;
+
+MRU_t* mru_create(void);
+void mru_destruct(MRU_t *mru);
+void mru_add(MRU_t *mru, const gchar *filename);
+void mru_remove(MRU_t *mru, const gchar *filename);
+void mru_set_first(MRU_t *mru, const gchar *filename);
+void mru_set_size(MRU_t *mru, gint size);
+void mru_write(MRU_t *mru, FILE *out);
+
+#define mru_empty(mru) ((mru)->list == NULL)
+
+#endif /* _IMAP_MRU_H */
diff --git a/plug-ins/imagemap/imap_ncsa.l b/plug-ins/imagemap/imap_ncsa.l
new file mode 100644
index 0000000..73b59f2
--- /dev/null
+++ b/plug-ins/imagemap/imap_ncsa.l
@@ -0,0 +1,112 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_ncsa_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+%}
+
+%option noyywrap
+%option noinput
+%option nounput
+
+DIGIT [0-9]
+ID [a-zA-Z_][a-zA-Z0-9_\-]*
+WS [ \t\n]+
+
+%x imap_link
+%x comment
+
+%%
+
+#\$AUTHOR: {
+ BEGIN(comment);
+ return AUTHOR;
+ }
+
+#\$TITLE: {
+ BEGIN(comment);
+ return TITLE;
+ }
+
+#\$DESCRIPTION: {
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+
+# {
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+
+<comment>.* {
+ BEGIN(INITIAL);
+ ncsa_lval.id = g_strndup (yytext, yyleng);
+ return COMMENT;
+ }
+
+RECT {
+ BEGIN(imap_link);
+ return RECTANGLE;
+ }
+
+CIRCLE {
+ BEGIN(imap_link);
+ return CIRCLE;
+ }
+
+POLY {
+ BEGIN(imap_link);
+ return POLYGON;
+ }
+
+DEFAULT {
+ BEGIN(imap_link);
+ return DEFAULT;
+ }
+
+<imap_link>[^ ,\t\n]+ {
+ BEGIN(INITIAL);
+ ncsa_lval.id = g_strndup (yytext, yyleng);
+ return LINK;
+ }
+
+-?{DIGIT}*"."?{DIGIT}*([Ee][-+]?{DIGIT}*)? {
+ ncsa_lval.value = g_ascii_strtod (yytext, NULL);
+ return FLOAT;
+ }
+
+{WS} ; /* Eat white space */
+
+. return *yytext;
+
+%%
+
+
diff --git a/plug-ins/imagemap/imap_ncsa.y b/plug-ins/imagemap/imap_ncsa.y
new file mode 100644
index 0000000..c93f62d
--- /dev/null
+++ b/plug-ins/imagemap/imap_ncsa.y
@@ -0,0 +1,195 @@
+%{
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <math.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int ncsa_lex(void);
+extern int ncsa_restart(FILE *ncsa_in);
+static void ncsa_error(char* s);
+
+static Object_t *current_object;
+
+%}
+
+%union {
+ int val;
+ double value;
+ char *id;
+}
+
+%token<val> RECTANGLE POLYGON CIRCLE DEFAULT
+%token<val> AUTHOR TITLE DESCRIPTION BEGIN_COMMENT
+%token<value> FLOAT
+%token<id> LINK COMMENT
+
+%%
+
+ncsa_file : comment_lines area_list
+ ;
+
+comment_lines : /* empty */
+ | comment_lines comment_line
+ ;
+
+comment_line : author_line
+ | title_line
+ | description_line
+ | real_comment
+ ;
+
+real_comment : BEGIN_COMMENT COMMENT
+ {
+ g_free ($2);
+ }
+ ;
+
+author_line : AUTHOR COMMENT
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->author, $2);
+ g_free ($2);
+ }
+ ;
+
+title_line : TITLE COMMENT
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->title, $2);
+ g_free ($2);
+ }
+ ;
+
+description_line: DESCRIPTION COMMENT
+ {
+ MapInfo_t *info = get_map_info();
+ gchar *description;
+
+ description = g_strconcat(info->description, $2, "\n",
+ NULL);
+ g_strreplace(&info->description, description);
+ g_free ($2);
+ }
+ ;
+
+area_list : /* Empty */
+ | area_list area
+ ;
+
+area : default
+ | rectangle
+ | circle
+ | polygon
+ | real_comment
+ ;
+
+default : DEFAULT LINK
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->default_url, $2);
+ g_free ($2);
+ }
+ ;
+
+
+rectangle : RECTANGLE LINK FLOAT ',' FLOAT FLOAT ',' FLOAT
+ {
+ gint x = (gint) $3;
+ gint y = (gint) $5;
+ gint width = (gint) fabs($6 - x);
+ gint height = (gint) fabs($8 - y);
+ current_object = create_rectangle(x, y, width, height);
+ object_set_url(current_object, $2);
+ add_shape(current_object);
+ g_free ($2);
+ }
+ ;
+
+circle : CIRCLE LINK FLOAT ',' FLOAT FLOAT ',' FLOAT
+ {
+ gint x = (gint) $3;
+ gint y = (gint) $5;
+ gint r = (gint) fabs($8 - $5);
+ current_object = create_circle(x, y, r);
+ object_set_url(current_object, $2);
+ add_shape(current_object);
+ g_free ($2);
+ }
+ ;
+
+polygon : POLYGON LINK {current_object = create_polygon(NULL);} coord_list
+ {
+ object_set_url(current_object, $2);
+ add_shape(current_object);
+ g_free ($2);
+ }
+ ;
+
+coord_list : /* Empty */
+ | coord_list coord
+ {
+ }
+ ;
+
+coord : FLOAT ',' FLOAT
+ {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GdkPoint *point = new_point((gint) $1, (gint) $3);
+ polygon->points = g_list_append(polygon->points,
+ (gpointer) point);
+ }
+ ;
+
+%%
+
+static void
+ncsa_error(char* s)
+{
+ extern FILE *ncsa_in;
+ ncsa_restart(ncsa_in);
+}
+
+gboolean
+load_ncsa(const char* filename)
+{
+ gboolean status;
+ extern FILE *ncsa_in;
+ ncsa_in = g_fopen(filename, "r");
+ if (ncsa_in) {
+ status = !ncsa_parse();
+ fclose(ncsa_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
diff --git a/plug-ins/imagemap/imap_ncsa_lex.c b/plug-ins/imagemap/imap_ncsa_lex.c
new file mode 100644
index 0000000..56f2fe1
--- /dev/null
+++ b/plug-ins/imagemap/imap_ncsa_lex.c
@@ -0,0 +1,1917 @@
+
+#line 3 "<stdout>"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer ncsa__create_buffer
+#define yy_delete_buffer ncsa__delete_buffer
+#define yy_flex_debug ncsa__flex_debug
+#define yy_init_buffer ncsa__init_buffer
+#define yy_flush_buffer ncsa__flush_buffer
+#define yy_load_buffer_state ncsa__load_buffer_state
+#define yy_switch_to_buffer ncsa__switch_to_buffer
+#define yyin ncsa_in
+#define yyleng ncsa_leng
+#define yylex ncsa_lex
+#define yylineno ncsa_lineno
+#define yyout ncsa_out
+#define yyrestart ncsa_restart
+#define yytext ncsa_text
+#define yywrap ncsa_wrap
+#define yyalloc ncsa_alloc
+#define yyrealloc ncsa_realloc
+#define yyfree ncsa_free
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 36
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE ncsa_restart(ncsa_in )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t ncsa_leng;
+
+extern FILE *ncsa_in, *ncsa_out;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up ncsa_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up ncsa_text again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via ncsa_restart()), so that the user can continue scanning by
+ * just pointing ncsa_in at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when ncsa_text is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t ncsa_leng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow ncsa_wrap()'s to do buffer switches
+ * instead of setting up a fresh ncsa_in. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void ncsa_restart (FILE *input_file );
+void ncsa__switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE ncsa__create_buffer (FILE *file,int size );
+void ncsa__delete_buffer (YY_BUFFER_STATE b );
+void ncsa__flush_buffer (YY_BUFFER_STATE b );
+void ncsa_push_buffer_state (YY_BUFFER_STATE new_buffer );
+void ncsa_pop_buffer_state (void );
+
+static void ncsa_ensure_buffer_stack (void );
+static void ncsa__load_buffer_state (void );
+static void ncsa__init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER ncsa__flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE ncsa__scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE ncsa__scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE ncsa__scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *ncsa_alloc (yy_size_t );
+void *ncsa_realloc (void *,yy_size_t );
+void ncsa_free (void * );
+
+#define yy_new_buffer ncsa__create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ ncsa_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ncsa__create_buffer(ncsa_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ ncsa_ensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ncsa__create_buffer(ncsa_in,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define ncsa_wrap() 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *ncsa_in = (FILE *) 0, *ncsa_out = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int ncsa_lineno;
+
+int ncsa_lineno = 1;
+
+extern char *ncsa_text;
+#define yytext_ptr ncsa_text
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up ncsa_text.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ ncsa_leng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 14
+#define YY_END_OF_BUFFER 15
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[76] =
+ { 0,
+ 11, 11, 0, 0, 5, 5, 15, 13, 12, 12,
+ 4, 11, 11, 11, 13, 13, 11, 13, 13, 10,
+ 14, 5, 12, 0, 11, 11, 11, 11, 0, 0,
+ 11, 11, 0, 0, 10, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 6,
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
+ 0, 0, 0, 9, 0, 0, 2, 1, 0, 0,
+ 0, 0, 0, 3, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 4, 5, 1, 1, 1, 1,
+ 1, 1, 6, 7, 8, 9, 1, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 11, 1, 1,
+ 1, 1, 1, 1, 12, 1, 13, 14, 15, 16,
+ 1, 17, 18, 1, 1, 19, 1, 20, 21, 22,
+ 1, 23, 24, 25, 26, 1, 1, 1, 27, 1,
+ 1, 1, 1, 1, 1, 1, 28, 1, 29, 30,
+
+ 31, 32, 1, 33, 34, 1, 1, 35, 1, 36,
+ 37, 38, 1, 39, 40, 41, 42, 1, 1, 1,
+ 43, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[44] =
+ { 0,
+ 1, 2, 3, 1, 1, 1, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[81] =
+ { 0,
+ 0, 38, 4, 14, 62, 61, 58, 178, 16, 22,
+ 49, 18, 35, 47, 2, 28, 64, 34, 48, 0,
+ 178, 0, 32, 61, 70, 72, 82, 83, 60, 68,
+ 34, 27, 75, 82, 0, 0, 70, 82, 86, 92,
+ 94, 80, 83, 84, 91, 91, 98, 92, 178, 178,
+ 102, 113, 108, 113, 110, 109, 113, 122, 178, 113,
+ 116, 122, 21, 178, 15, 119, 178, 178, 122, 130,
+ 128, 130, 1, 178, 178, 166, 169, 172, 0, 175
+ } ;
+
+static yyconst flex_int16_t yy_def[81] =
+ { 0,
+ 76, 76, 77, 77, 78, 78, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 79,
+ 75, 80, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 79, 80, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 0, 75, 75, 75, 75, 75
+ } ;
+
+static yyconst flex_int16_t yy_nxt[222] =
+ { 0,
+ 35, 9, 10, 11, 75, 21, 21, 12, 13, 14,
+ 21, 74, 15, 16, 17, 21, 21, 23, 23, 29,
+ 21, 18, 19, 23, 23, 68, 25, 26, 15, 16,
+ 17, 67, 27, 23, 23, 29, 32, 18, 19, 9,
+ 10, 11, 30, 32, 28, 12, 13, 14, 27, 27,
+ 15, 16, 17, 24, 33, 25, 26, 75, 30, 18,
+ 19, 27, 34, 21, 21, 27, 15, 16, 17, 31,
+ 33, 31, 37, 32, 38, 18, 19, 27, 34, 28,
+ 25, 26, 40, 41, 27, 39, 27, 31, 37, 31,
+ 38, 32, 28, 42, 43, 44, 45, 27, 40, 41,
+
+ 27, 39, 27, 46, 47, 48, 49, 50, 51, 42,
+ 43, 44, 45, 27, 52, 53, 54, 55, 56, 46,
+ 47, 48, 49, 50, 51, 57, 58, 59, 60, 61,
+ 52, 53, 54, 55, 56, 62, 63, 64, 65, 66,
+ 69, 57, 58, 59, 60, 61, 70, 71, 72, 73,
+ 75, 62, 63, 64, 65, 66, 69, 75, 75, 75,
+ 75, 75, 70, 71, 72, 73, 8, 8, 8, 20,
+ 20, 20, 22, 22, 22, 36, 36, 7, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75
+ } ;
+
+static yyconst flex_int16_t yy_chk[222] =
+ { 0,
+ 79, 1, 1, 1, 0, 3, 3, 1, 1, 1,
+ 3, 73, 1, 1, 1, 4, 4, 9, 9, 15,
+ 4, 1, 1, 10, 10, 65, 12, 12, 1, 1,
+ 1, 63, 12, 23, 23, 15, 32, 1, 1, 2,
+ 2, 2, 16, 31, 13, 2, 2, 2, 12, 13,
+ 2, 2, 2, 11, 18, 14, 14, 7, 16, 2,
+ 2, 14, 19, 6, 5, 13, 2, 2, 2, 17,
+ 18, 17, 24, 17, 24, 2, 2, 14, 19, 25,
+ 26, 26, 29, 30, 25, 24, 26, 27, 24, 27,
+ 24, 27, 28, 33, 34, 37, 38, 28, 29, 30,
+
+ 25, 24, 26, 39, 40, 41, 42, 43, 44, 33,
+ 34, 37, 38, 28, 45, 46, 47, 48, 51, 39,
+ 40, 41, 42, 43, 44, 52, 53, 54, 55, 56,
+ 45, 46, 47, 48, 51, 57, 58, 60, 61, 62,
+ 66, 52, 53, 54, 55, 56, 69, 70, 71, 72,
+ 0, 57, 58, 60, 61, 62, 66, 0, 0, 0,
+ 0, 0, 69, 70, 71, 72, 76, 76, 76, 77,
+ 77, 77, 78, 78, 78, 80, 80, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int ncsa__flex_debug;
+int ncsa__flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *ncsa_text;
+#line 1 "imap_ncsa.l"
+#line 2 "imap_ncsa.l"
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <string.h>
+
+#include <glib.h>
+
+#include "imap_ncsa_parse.h"
+
+#ifdef FLEX_SCANNER
+#define YY_NO_UNPUT
+#endif /* FLEX_SCANNER */
+
+#define YY_NO_INPUT 1
+
+
+#line 581 "<stdout>"
+
+#define INITIAL 0
+#define imap_link 1
+#define comment 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int ncsa_lex_destroy (void );
+
+int ncsa_get_debug (void );
+
+void ncsa_set_debug (int debug_flag );
+
+YY_EXTRA_TYPE ncsa_get_extra (void );
+
+void ncsa_set_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *ncsa_get_in (void );
+
+void ncsa_set_in (FILE * in_str );
+
+FILE *ncsa_get_out (void );
+
+void ncsa_set_out (FILE * out_str );
+
+yy_size_t ncsa_get_leng (void );
+
+char *ncsa_get_text (void );
+
+int ncsa_get_lineno (void );
+
+void ncsa_set_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int ncsa_wrap (void );
+#else
+extern int ncsa_wrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( ncsa_text, ncsa_leng, 1, ncsa_out )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( ncsa_in )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( ncsa_in ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, ncsa_in))==0 && ferror(ncsa_in)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(ncsa_in); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int ncsa_lex (void);
+
+#define YY_DECL int ncsa_lex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after ncsa_text and ncsa_leng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 47 "imap_ncsa.l"
+
+
+#line 766 "<stdout>"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! ncsa_in )
+ ncsa_in = stdin;
+
+ if ( ! ncsa_out )
+ ncsa_out = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ ncsa_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ncsa__create_buffer(ncsa_in,YY_BUF_SIZE );
+ }
+
+ ncsa__load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of ncsa_text. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 76 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 178 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 49 "imap_ncsa.l"
+{
+ BEGIN(comment);
+ return AUTHOR;
+ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 54 "imap_ncsa.l"
+{
+ BEGIN(comment);
+ return TITLE;
+ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 59 "imap_ncsa.l"
+{
+ BEGIN(comment);
+ return DESCRIPTION;
+ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 64 "imap_ncsa.l"
+{
+ BEGIN(comment);
+ return BEGIN_COMMENT;
+ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 69 "imap_ncsa.l"
+{
+ BEGIN(INITIAL);
+ ncsa_lval.id = g_strndup (ncsa_text, ncsa_leng);
+ return COMMENT;
+ }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 75 "imap_ncsa.l"
+{
+ BEGIN(imap_link);
+ return RECTANGLE;
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 80 "imap_ncsa.l"
+{
+ BEGIN(imap_link);
+ return CIRCLE;
+ }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 85 "imap_ncsa.l"
+{
+ BEGIN(imap_link);
+ return POLYGON;
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 90 "imap_ncsa.l"
+{
+ BEGIN(imap_link);
+ return DEFAULT;
+ }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 95 "imap_ncsa.l"
+{
+ BEGIN(INITIAL);
+ ncsa_lval.id = g_strndup (ncsa_text, ncsa_leng);
+ return LINK;
+ }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 101 "imap_ncsa.l"
+{
+ ncsa_lval.value = g_ascii_strtod (ncsa_text, NULL);
+ return FLOAT;
+ }
+ YY_BREAK
+case 12:
+/* rule 12 can match eol */
+YY_RULE_SETUP
+#line 106 "imap_ncsa.l"
+; /* Eat white space */
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 108 "imap_ncsa.l"
+return *ncsa_text;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 110 "imap_ncsa.l"
+ECHO;
+ YY_BREAK
+#line 955 "<stdout>"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(imap_link):
+case YY_STATE_EOF(comment):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed ncsa_in at a new source and called
+ * ncsa_lex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = ncsa_in;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( ncsa_wrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * ncsa_text, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of ncsa_lex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ ncsa_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ ncsa_restart(ncsa_in );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ncsa_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 76 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 76 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 75);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ ncsa_restart(ncsa_in );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( ncsa_wrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve ncsa_text */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void ncsa_restart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ ncsa_ensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ncsa__create_buffer(ncsa_in,YY_BUF_SIZE );
+ }
+
+ ncsa__init_buffer(YY_CURRENT_BUFFER,input_file );
+ ncsa__load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void ncsa__switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * ncsa_pop_buffer_state();
+ * ncsa_push_buffer_state(new_buffer);
+ */
+ ncsa_ensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ ncsa__load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (ncsa_wrap()) processing, but the only time this flag
+ * is looked at is after ncsa_wrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void ncsa__load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ ncsa_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE ncsa__create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) ncsa_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa__create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) ncsa_alloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa__create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ ncsa__init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with ncsa__create_buffer()
+ *
+ */
+ void ncsa__delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ ncsa_free((void *) b->yy_ch_buf );
+
+ ncsa_free((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a ncsa_restart() or at EOF.
+ */
+ static void ncsa__init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ ncsa__flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then ncsa__init_buffer was _probably_
+ * called from ncsa_restart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void ncsa__flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ ncsa__load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void ncsa_push_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ ncsa_ensure_buffer_stack();
+
+ /* This block is copied from ncsa__switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from ncsa__switch_to_buffer. */
+ ncsa__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void ncsa_pop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ ncsa__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ ncsa__load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void ncsa_ensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)ncsa_alloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa_ensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)ncsa_realloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa_ensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ncsa__scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) ncsa_alloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa__scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ ncsa__switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to ncsa_lex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * ncsa__scan_bytes() instead.
+ */
+YY_BUFFER_STATE ncsa__scan_string (yyconst char * yystr )
+{
+
+ return ncsa__scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to ncsa_lex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ncsa__scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) ncsa_alloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ncsa__scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = ncsa__scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in ncsa__scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up ncsa_text. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ ncsa_text[ncsa_leng] = (yy_hold_char); \
+ (yy_c_buf_p) = ncsa_text + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ ncsa_leng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int ncsa_get_lineno (void)
+{
+
+ return ncsa_lineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *ncsa_get_in (void)
+{
+ return ncsa_in;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *ncsa_get_out (void)
+{
+ return ncsa_out;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t ncsa_get_leng (void)
+{
+ return ncsa_leng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *ncsa_get_text (void)
+{
+ return ncsa_text;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void ncsa_set_lineno (int line_number )
+{
+
+ ncsa_lineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see ncsa__switch_to_buffer
+ */
+void ncsa_set_in (FILE * in_str )
+{
+ ncsa_in = in_str ;
+}
+
+void ncsa_set_out (FILE * out_str )
+{
+ ncsa_out = out_str ;
+}
+
+int ncsa_get_debug (void)
+{
+ return ncsa__flex_debug;
+}
+
+void ncsa_set_debug (int bdebug )
+{
+ ncsa__flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from ncsa_lex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ ncsa_in = stdin;
+ ncsa_out = stdout;
+#else
+ ncsa_in = (FILE *) 0;
+ ncsa_out = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * ncsa_lex_init()
+ */
+ return 0;
+}
+
+/* ncsa_lex_destroy is for both reentrant and non-reentrant scanners. */
+int ncsa_lex_destroy (void)
+{
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ ncsa__delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ ncsa_pop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ ncsa_free((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * ncsa_lex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *ncsa_alloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *ncsa_realloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void ncsa_free (void * ptr )
+{
+ free( (char *) ptr ); /* see ncsa_realloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 110 "imap_ncsa.l"
+
+
+
+
+
diff --git a/plug-ins/imagemap/imap_ncsa_parse.c b/plug-ins/imagemap/imap_ncsa_parse.c
new file mode 100644
index 0000000..d2bdf47
--- /dev/null
+++ b/plug-ins/imagemap/imap_ncsa_parse.c
@@ -0,0 +1,1830 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.6.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse ncsa_parse
+#define yylex ncsa_lex
+#define yyerror ncsa_error
+#define yylval ncsa_lval
+#define yychar ncsa_char
+#define yydebug ncsa_debug
+#define yynerrs ncsa_nerrs
+
+/* Copy the first part of user declarations. */
+/* Line 336 of yacc.c */
+#line 1 "imap_ncsa.y"
+
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <math.h>
+
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_circle.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_polygon.h"
+#include "imap_rectangle.h"
+#include "imap_string.h"
+
+extern int ncsa_lex(void);
+extern int ncsa_restart(FILE *ncsa_in);
+static void ncsa_error(char* s);
+
+static Object_t *current_object;
+
+
+/* Line 336 of yacc.c */
+#line 119 "y.tab.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef NCSA_Y_TAB_H
+# define NCSA_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int ncsa_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ RECTANGLE = 258,
+ POLYGON = 259,
+ CIRCLE = 260,
+ DEFAULT = 261,
+ AUTHOR = 262,
+ TITLE = 263,
+ DESCRIPTION = 264,
+ BEGIN_COMMENT = 265,
+ FLOAT = 266,
+ LINK = 267,
+ COMMENT = 268
+ };
+#endif
+/* Tokens. */
+#define RECTANGLE 258
+#define POLYGON 259
+#define CIRCLE 260
+#define DEFAULT 261
+#define AUTHOR 262
+#define TITLE 263
+#define DESCRIPTION 264
+#define BEGIN_COMMENT 265
+#define FLOAT 266
+#define LINK 267
+#define COMMENT 268
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 350 of yacc.c */
+#line 45 "imap_ncsa.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 350 of yacc.c */
+#line 195 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE ncsa_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int ncsa_parse (void *YYPARSE_PARAM);
+#else
+int ncsa_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int ncsa_parse (void);
+#else
+int ncsa_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !NCSA_Y_TAB_H */
+
+/* Copy the second part of user declarations. */
+
+/* Line 353 of yacc.c */
+#line 223 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 3
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 35
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 15
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 17
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 27
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 50
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 268
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 14, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 6, 7, 10, 12, 14, 16, 18,
+ 21, 24, 27, 30, 31, 34, 36, 38, 40, 42,
+ 44, 47, 56, 65, 66, 71, 72, 75
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 16, 0, -1, 17, 23, -1, -1, 17, 18, -1,
+ 20, -1, 21, -1, 22, -1, 19, -1, 10, 13,
+ -1, 7, 13, -1, 8, 13, -1, 9, 13, -1,
+ -1, 23, 24, -1, 25, -1, 26, -1, 27, -1,
+ 28, -1, 19, -1, 6, 12, -1, 3, 12, 11,
+ 14, 11, 11, 14, 11, -1, 5, 12, 11, 14,
+ 11, 11, 14, 11, -1, -1, 4, 12, 29, 30,
+ -1, -1, 30, 31, -1, 11, 14, 11, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 58, 58, 61, 62, 65, 66, 67, 68, 71,
+ 77, 85, 93, 105, 106, 109, 110, 111, 112, 113,
+ 116, 125, 138, 150, 150, 158, 159, 164
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "RECTANGLE", "POLYGON", "CIRCLE",
+ "DEFAULT", "AUTHOR", "TITLE", "DESCRIPTION", "BEGIN_COMMENT", "FLOAT",
+ "LINK", "COMMENT", "','", "$accept", "ncsa_file", "comment_lines",
+ "comment_line", "real_comment", "author_line", "title_line",
+ "description_line", "area_list", "area", "default", "rectangle",
+ "circle", "polygon", "$@1", "coord_list", "coord", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 44
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 15, 16, 17, 17, 18, 18, 18, 18, 19,
+ 20, 21, 22, 23, 23, 24, 24, 24, 24, 24,
+ 25, 26, 27, 29, 28, 30, 30, 31
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 0, 2, 1, 1, 1, 1, 2,
+ 2, 2, 2, 0, 2, 1, 1, 1, 1, 1,
+ 2, 8, 8, 0, 4, 0, 2, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 3, 0, 13, 1, 0, 0, 0, 0, 4, 8,
+ 5, 6, 7, 2, 10, 11, 12, 9, 0, 0,
+ 0, 0, 19, 14, 15, 16, 17, 18, 0, 23,
+ 0, 20, 0, 25, 0, 0, 24, 0, 0, 0,
+ 26, 0, 0, 0, 0, 0, 27, 0, 21, 22
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 2, 8, 9, 10, 11, 12, 13, 23,
+ 24, 25, 26, 27, 33, 36, 40
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -9
+static const yytype_int8 yypact[] =
+{
+ -9, 4, 1, -9, -8, -7, -1, 0, -9, -9,
+ -9, -9, -9, -3, -9, -9, -9, -9, 2, 3,
+ 5, 6, -9, -9, -9, -9, -9, -9, 8, -9,
+ 9, -9, 7, -9, 10, 11, 12, 14, 15, 13,
+ -9, 17, 16, 18, 19, 20, -9, 21, -9, -9
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -9, -9, -9, -9, 22, -9, -9, -9, -9, -9,
+ -9, -9, -9, -9, -9, -9, -9
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 18, 19, 20, 21, 3, 14, 15, 7, 4, 5,
+ 6, 7, 16, 17, 28, 29, 0, 30, 31, 32,
+ 34, 35, 38, 39, 37, 41, 42, 43, 44, 46,
+ 45, 48, 49, 47, 0, 22
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-9))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int8 yycheck[] =
+{
+ 3, 4, 5, 6, 0, 13, 13, 10, 7, 8,
+ 9, 10, 13, 13, 12, 12, -1, 12, 12, 11,
+ 11, 14, 11, 11, 14, 11, 11, 14, 11, 11,
+ 14, 11, 11, 14, -1, 13
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 16, 17, 0, 7, 8, 9, 10, 18, 19,
+ 20, 21, 22, 23, 13, 13, 13, 13, 3, 4,
+ 5, 6, 19, 24, 25, 26, 27, 28, 12, 12,
+ 12, 12, 11, 29, 11, 14, 30, 14, 11, 11,
+ 31, 11, 11, 14, 11, 14, 11, 14, 11, 11
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 9:
+/* Line 1787 of yacc.c */
+#line 72 "imap_ncsa.y"
+ {
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 10:
+/* Line 1787 of yacc.c */
+#line 78 "imap_ncsa.y"
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->author, (yyvsp[(2) - (2)].id));
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 11:
+/* Line 1787 of yacc.c */
+#line 86 "imap_ncsa.y"
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->title, (yyvsp[(2) - (2)].id));
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 12:
+/* Line 1787 of yacc.c */
+#line 94 "imap_ncsa.y"
+ {
+ MapInfo_t *info = get_map_info();
+ gchar *description;
+
+ description = g_strconcat(info->description, (yyvsp[(2) - (2)].id), "\n",
+ NULL);
+ g_strreplace(&info->description, description);
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 20:
+/* Line 1787 of yacc.c */
+#line 117 "imap_ncsa.y"
+ {
+ MapInfo_t *info = get_map_info();
+ g_strreplace(&info->default_url, (yyvsp[(2) - (2)].id));
+ g_free ((yyvsp[(2) - (2)].id));
+ }
+ break;
+
+ case 21:
+/* Line 1787 of yacc.c */
+#line 126 "imap_ncsa.y"
+ {
+ gint x = (gint) (yyvsp[(3) - (8)].value);
+ gint y = (gint) (yyvsp[(5) - (8)].value);
+ gint width = (gint) fabs((yyvsp[(6) - (8)].value) - x);
+ gint height = (gint) fabs((yyvsp[(8) - (8)].value) - y);
+ current_object = create_rectangle(x, y, width, height);
+ object_set_url(current_object, (yyvsp[(2) - (8)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(2) - (8)].id));
+ }
+ break;
+
+ case 22:
+/* Line 1787 of yacc.c */
+#line 139 "imap_ncsa.y"
+ {
+ gint x = (gint) (yyvsp[(3) - (8)].value);
+ gint y = (gint) (yyvsp[(5) - (8)].value);
+ gint r = (gint) fabs((yyvsp[(8) - (8)].value) - (yyvsp[(5) - (8)].value));
+ current_object = create_circle(x, y, r);
+ object_set_url(current_object, (yyvsp[(2) - (8)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(2) - (8)].id));
+ }
+ break;
+
+ case 23:
+/* Line 1787 of yacc.c */
+#line 150 "imap_ncsa.y"
+ {current_object = create_polygon(NULL);}
+ break;
+
+ case 24:
+/* Line 1787 of yacc.c */
+#line 151 "imap_ncsa.y"
+ {
+ object_set_url(current_object, (yyvsp[(2) - (4)].id));
+ add_shape(current_object);
+ g_free ((yyvsp[(2) - (4)].id));
+ }
+ break;
+
+ case 26:
+/* Line 1787 of yacc.c */
+#line 160 "imap_ncsa.y"
+ {
+ }
+ break;
+
+ case 27:
+/* Line 1787 of yacc.c */
+#line 165 "imap_ncsa.y"
+ {
+ Polygon_t *polygon = ObjectToPolygon(current_object);
+ GdkPoint *point = new_point((gint) (yyvsp[(1) - (3)].value), (gint) (yyvsp[(3) - (3)].value));
+ polygon->points = g_list_append(polygon->points,
+ (gpointer) point);
+ }
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 1577 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2048 of yacc.c */
+#line 173 "imap_ncsa.y"
+
+
+static void
+ncsa_error(char* s)
+{
+ extern FILE *ncsa_in;
+ ncsa_restart(ncsa_in);
+}
+
+gboolean
+load_ncsa(const char* filename)
+{
+ gboolean status;
+ extern FILE *ncsa_in;
+ ncsa_in = g_fopen(filename, "r");
+ if (ncsa_in) {
+ status = !ncsa_parse();
+ fclose(ncsa_in);
+ } else {
+ status = FALSE;
+ }
+ return status;
+}
+
diff --git a/plug-ins/imagemap/imap_ncsa_parse.h b/plug-ins/imagemap/imap_ncsa_parse.h
new file mode 100644
index 0000000..68791a2
--- /dev/null
+++ b/plug-ins/imagemap/imap_ncsa_parse.h
@@ -0,0 +1,112 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef NCSA_Y_TAB_H
+# define NCSA_Y_TAB_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int ncsa_debug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ RECTANGLE = 258,
+ POLYGON = 259,
+ CIRCLE = 260,
+ DEFAULT = 261,
+ AUTHOR = 262,
+ TITLE = 263,
+ DESCRIPTION = 264,
+ BEGIN_COMMENT = 265,
+ FLOAT = 266,
+ LINK = 267,
+ COMMENT = 268
+ };
+#endif
+/* Tokens. */
+#define RECTANGLE 258
+#define POLYGON 259
+#define CIRCLE 260
+#define DEFAULT 261
+#define AUTHOR 262
+#define TITLE 263
+#define DESCRIPTION 264
+#define BEGIN_COMMENT 265
+#define FLOAT 266
+#define LINK 267
+#define COMMENT 268
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2049 of yacc.c */
+#line 45 "imap_ncsa.y"
+
+ int val;
+ double value;
+ char *id;
+
+
+/* Line 2049 of yacc.c */
+#line 90 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE ncsa_lval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int ncsa_parse (void *YYPARSE_PARAM);
+#else
+int ncsa_parse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int ncsa_parse (void);
+#else
+int ncsa_parse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !NCSA_Y_TAB_H */
diff --git a/plug-ins/imagemap/imap_object.c b/plug-ins/imagemap/imap_object.c
new file mode 100644
index 0000000..2f06e92
--- /dev/null
+++ b/plug-ins/imagemap/imap_object.c
@@ -0,0 +1,1040 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_default_dialog.h"
+#include "imap_grid.h"
+#include "imap_main.h"
+#include "imap_object.h"
+#include "imap_string.h"
+
+typedef struct {
+ ObjectListCallbackFunc_t func;
+ gpointer data;
+} ObjectListCB_t;
+
+static ObjectList_t *_paste_buffer;
+
+static gpointer
+object_list_callback_add(ObjectListCallback_t *list,
+ ObjectListCallbackFunc_t func, gpointer data)
+{
+ ObjectListCB_t *cb = g_new(ObjectListCB_t, 1);
+ cb->func = func;
+ cb->data = data;
+ list->list = g_list_append(list->list, cb);
+ return cb;
+}
+
+static void
+object_list_callback_remove(ObjectListCallback_t *list, gpointer id)
+{
+ list->list = g_list_remove(list->list, id);
+}
+
+static void
+object_list_callback_call(ObjectListCallback_t *list, Object_t *obj)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ ObjectListCB_t *cb = (ObjectListCB_t*) p->data;
+ cb->func(obj, cb->data);
+ }
+}
+
+gpointer
+object_list_add_changed_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->changed_cb, func, data);
+}
+
+gpointer
+object_list_add_update_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->update_cb, func, data);
+}
+
+gpointer
+object_list_add_add_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->add_cb, func, data);
+}
+
+gpointer
+object_list_add_remove_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->remove_cb, func, data);
+}
+
+gpointer
+object_list_add_select_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->select_cb, func, data);
+}
+
+gpointer
+object_list_add_move_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->move_cb, func, data);
+}
+
+gpointer
+object_list_add_geometry_cb(ObjectList_t *list, ObjectListCallbackFunc_t func,
+ gpointer data)
+{
+ return object_list_callback_add(&list->geometry_cb, func, data);
+}
+
+gpointer
+paste_buffer_add_add_cb(ObjectListCallbackFunc_t func, gpointer data)
+{
+ if (!_paste_buffer)
+ _paste_buffer = make_object_list();
+ return object_list_callback_add(&_paste_buffer->add_cb, func, data);
+}
+
+gpointer
+paste_buffer_add_remove_cb(ObjectListCallbackFunc_t func, gpointer data)
+{
+ if (!_paste_buffer)
+ _paste_buffer = make_object_list();
+ return object_list_callback_add(&_paste_buffer->remove_cb, func, data);
+}
+
+void
+object_list_remove_add_cb(ObjectList_t *list, gpointer id)
+{
+ object_list_callback_remove(&list->add_cb, id);
+}
+
+void
+object_list_remove_select_cb(ObjectList_t *list, gpointer id)
+{
+ object_list_callback_remove(&list->select_cb, id);
+}
+
+void
+object_list_remove_remove_cb(ObjectList_t *list, gpointer id)
+{
+ object_list_callback_remove(&list->remove_cb, id);
+}
+
+void
+object_list_remove_move_cb(ObjectList_t *list, gpointer id)
+{
+ object_list_callback_remove(&list->move_cb, id);
+}
+
+void
+object_list_remove_geometry_cb(ObjectList_t *list, gpointer id)
+{
+ object_list_callback_remove(&list->geometry_cb, id);
+}
+
+Object_t*
+object_init(Object_t *obj, ObjectClass_t *class)
+{
+ obj->class = class;
+ obj->refcount = 1;
+ obj->selected = FALSE;
+ obj->locked = FALSE;
+ obj->url = g_strdup("");
+ obj->target = g_strdup("");
+ obj->comment = g_strdup("");
+ obj->mouse_over = g_strdup("");
+ obj->mouse_out = g_strdup("");
+ obj->focus = g_strdup("");
+ obj->blur = g_strdup("");
+ return obj;
+}
+
+static void
+object_destruct(Object_t *obj)
+{
+ if (obj->class->destruct)
+ obj->class->destruct(obj);
+ g_free(obj->url);
+ g_free(obj->target);
+ g_free(obj->comment);
+ g_free(obj->mouse_over);
+ g_free(obj->mouse_out);
+ g_free(obj->focus);
+ g_free(obj->blur);
+ g_free(obj);
+}
+
+Object_t*
+object_ref(Object_t *obj)
+{
+ obj->refcount++;
+ return obj;
+}
+
+void
+object_unref(Object_t *obj)
+{
+ if (!--obj->refcount)
+ object_destruct(obj);
+}
+
+Object_t*
+object_clone(Object_t *obj)
+{
+ Object_t *clone = obj->class->clone(obj);
+ clone->class = obj->class;
+ clone->refcount = 1;
+ clone->selected = obj->selected;
+ clone->locked = FALSE;
+ clone->url = g_strdup(obj->url);
+ clone->target = g_strdup(obj->target);
+ clone->comment = g_strdup(obj->comment);
+ clone->mouse_over = g_strdup(obj->mouse_over);
+ clone->mouse_out = g_strdup(obj->mouse_out);
+ clone->focus = g_strdup(obj->focus);
+ clone->blur = g_strdup(obj->blur);
+ return clone;
+}
+
+static Object_t*
+object_copy(Object_t *src, Object_t *des)
+{
+ des->class = src->class;
+ des->selected = src->selected;
+ des->locked = FALSE;
+ g_strreplace(&des->url, src->url);
+ g_strreplace(&des->target, src->target);
+ g_strreplace(&des->comment, src->comment);
+ g_strreplace(&des->mouse_over, src->mouse_over);
+ g_strreplace(&des->mouse_out, src->mouse_out);
+ g_strreplace(&des->focus, src->focus);
+ g_strreplace(&des->blur, src->blur);
+ return des;
+}
+
+Object_t*
+object_assign(Object_t *obj, Object_t *des)
+{
+ obj->class->assign(obj, des);
+ return object_copy(obj, des);
+}
+
+void
+object_draw(Object_t *obj, cairo_t *cr)
+{
+ PreferencesData_t *preferences = get_preferences();
+ ColorSelData_t *colors = &preferences->colors;
+ GdkColor *fg, *bg;
+ gdouble dash = 4.;
+
+ if (obj->selected & 4) {
+ fg = &colors->interactive_fg;
+ bg = &colors->interactive_bg;
+ obj->selected &= ~4;
+ } else if (obj->selected) {
+ fg = &colors->selected_fg;
+ bg = &colors->selected_bg;
+ } else {
+ fg = &colors->normal_fg;
+ bg = &colors->normal_bg;
+ }
+
+ cairo_save (cr);
+ gdk_cairo_set_source_color (cr, bg);
+ obj->class->draw(obj, cr);
+ gdk_cairo_set_source_color (cr, fg);
+ cairo_set_dash (cr, &dash, 1, 0.);
+ obj->class->draw(obj, cr);
+
+ if (obj->selected && preferences->show_area_handle)
+ obj->class->draw_sashes(obj, cr);
+ cairo_restore (cr);
+}
+
+void
+object_edit(Object_t *obj, gboolean add)
+{
+ if (!obj->class->info_dialog)
+ obj->class->info_dialog = create_edit_area_info_dialog(obj);
+ edit_area_info_dialog_show(obj->class->info_dialog, obj, add);
+}
+
+void
+object_select(Object_t *obj)
+{
+ obj->selected = TRUE;
+ object_list_callback_call(&obj->list->select_cb, obj);
+ object_emit_geometry_signal(obj);
+}
+
+void
+object_unselect(Object_t *obj)
+{
+ obj->selected = FALSE;
+ object_list_callback_call(&obj->list->select_cb, obj);
+ object_emit_geometry_signal(obj);
+}
+
+void
+object_move(Object_t *obj, gint dx, gint dy)
+{
+ obj->class->move(obj, dx, dy);
+ object_emit_geometry_signal(obj);
+}
+
+void
+object_move_sash(Object_t *obj, gint dx, gint dy)
+{
+ gint x, y, width, height;
+ MoveSashFunc_t sash_func;
+
+ obj->class->get_dimensions(obj, &x, &y, &width, &height);
+ if (dx == 0)
+ x += (width / 2);
+ else
+ x += width;
+
+ if (dy == 0)
+ y += (height / 2);
+ else
+ y += height;
+
+ sash_func = obj->class->near_sash(obj, x, y);
+
+ if (sash_func) {
+ sash_func(obj, dx, dy);
+ object_emit_geometry_signal(obj);
+ }
+}
+
+void
+object_remove(Object_t *obj)
+{
+ object_list_remove(obj->list, obj);
+ object_emit_geometry_signal(obj);
+}
+
+void
+object_lock(Object_t *obj)
+{
+ obj->locked = TRUE;
+}
+
+void
+object_unlock(Object_t *obj)
+{
+ obj->locked = FALSE;
+}
+
+void
+object_set_url(Object_t *obj, const gchar *url)
+{
+ g_strreplace(&obj->url, url);
+}
+
+void
+object_set_target(Object_t *obj, const gchar *target)
+{
+ g_strreplace(&obj->target, target);
+}
+
+void
+object_set_comment(Object_t *obj, const gchar *comment)
+{
+ g_strreplace(&obj->comment, comment);
+}
+
+void
+object_set_mouse_over(Object_t *obj, const gchar *mouse_over)
+{
+ g_strreplace(&obj->mouse_over, mouse_over);
+}
+
+void
+object_set_mouse_out(Object_t *obj, const gchar *mouse_out)
+{
+ g_strreplace(&obj->mouse_out, mouse_out);
+}
+
+void
+object_set_focus(Object_t *obj, const gchar *focus)
+{
+ g_strreplace(&obj->focus, focus);
+}
+
+void
+object_set_blur(Object_t *obj, const gchar *blur)
+{
+ g_strreplace(&obj->blur, blur);
+}
+
+gint
+object_get_position_in_list(Object_t *obj)
+{
+ return g_list_index(obj->list->list, (gpointer) obj);
+}
+
+void
+object_emit_changed_signal(Object_t *obj)
+{
+ object_list_callback_call(&obj->list->changed_cb, obj);
+}
+
+void
+object_emit_geometry_signal(Object_t *obj)
+{
+ object_list_callback_call(&obj->list->geometry_cb, obj);
+}
+
+void
+object_emit_update_signal(Object_t *obj)
+{
+ object_list_callback_call(&obj->list->update_cb, obj);
+}
+
+void
+do_object_locked_dialog(void)
+{
+ static DefaultDialog_t *dialog;
+ if (!dialog) {
+ dialog = make_default_dialog("Object locked");
+ default_dialog_hide_cancel_button(dialog);
+ default_dialog_hide_apply_button(dialog);
+ default_dialog_set_label(
+ dialog,
+ "\n You cannot delete the selected object \n"
+ "since it is currently being edited.\n");
+ }
+ default_dialog_show(dialog);
+}
+
+static Object_t*
+object_factory_create_object(ObjectFactory_t *factory, gint x, gint y)
+{
+ return factory->obj = factory->create_object(x, y);
+}
+
+static gboolean
+button_motion(GtkWidget *widget, GdkEventMotion *event,
+ ObjectFactory_t *factory)
+{
+ gint x = get_real_coord((gint) event->x);
+ gint y = get_real_coord((gint) event->y);
+
+ round_to_grid(&x, &y);
+
+ factory->set_xy(factory->obj, event->state, x, y);
+
+ preview_redraw ();
+
+ return FALSE;
+}
+
+gboolean
+object_on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ static ObjectFactory_t *factory;
+ PreferencesData_t *preferences = get_preferences();
+ gint x = get_real_coord((gint) event->x);
+ gint y = get_real_coord((gint) event->y);
+ static Object_t *obj;
+
+ if (event->type == GDK_2BUTTON_PRESS)
+ return FALSE;
+ round_to_grid(&x, &y);
+
+ if (obj) {
+ if (event->button == 1) {
+ if (!factory->finish || factory->finish(obj, x, y)) {
+ g_signal_handlers_disconnect_by_func(widget,
+ button_motion,
+ factory);
+ if (object_is_valid(obj)) {
+ Command_t *command = create_command_new(get_shapes(), obj);
+ command_execute(command);
+ if (preferences->prompt_for_area_info)
+ object_edit(obj, FALSE);
+ } else {
+ object_unref(obj);
+ }
+ preview_unset_tmp_obj (obj);
+ preview_redraw ();
+ obj = NULL;
+ main_clear_dimension();
+ }
+ } else if (event->button == 3) {
+ if (!factory->cancel || factory->cancel(event, obj)) {
+ g_signal_handlers_disconnect_by_func(widget,
+ button_motion,
+ factory);
+ object_unref(obj);
+ preview_unset_tmp_obj (obj);
+ preview_redraw ();
+ obj = NULL;
+ main_clear_dimension();
+ }
+ return TRUE;
+ }
+ } else {
+ if (event->button == 1) {
+ factory = ((ObjectFactory_t*(*)(guint)) data)(event->state);
+ obj = object_factory_create_object(factory, x, y);
+ preview_set_tmp_obj (obj);
+
+ g_signal_connect(widget, "motion-notify-event",
+ G_CALLBACK(button_motion), factory);
+ }
+ }
+ return FALSE;
+}
+
+ObjectList_t*
+make_object_list(void)
+{
+ return g_new0 (ObjectList_t, 1);
+}
+
+void
+object_list_destruct(ObjectList_t *list)
+{
+ object_list_remove_all(list);
+ g_free(list->list);
+}
+
+ObjectList_t*
+object_list_append_list(ObjectList_t *des, ObjectList_t *src)
+{
+ GList *p;
+ if (!src)
+ return des;
+ for (p = src->list; p; p = p->next)
+ object_list_append(des, object_clone((Object_t*) p->data));
+ object_list_set_changed(des, TRUE);
+ return des;
+}
+
+ObjectList_t*
+object_list_copy(ObjectList_t *des, ObjectList_t *src)
+{
+ if (des)
+ object_list_remove_all(des);
+ else
+ des = make_object_list();
+
+ return object_list_append_list(des, src);
+}
+
+void
+object_list_append(ObjectList_t *list, Object_t *object)
+{
+ object->list = list;
+ list->list = g_list_append(list->list, (gpointer) object);
+ object_list_set_changed(list, TRUE);
+ object_list_callback_call(&list->add_cb, object);
+}
+
+void
+object_list_prepend(ObjectList_t *list, Object_t *object)
+{
+ object->list = list;
+ list->list = g_list_prepend(list->list, (gpointer) object);
+ object_list_set_changed(list, TRUE);
+ object_list_callback_call(&list->add_cb, object);
+}
+
+void
+object_list_insert(ObjectList_t *list, gint position, Object_t *object)
+{
+ object->list = list;
+ list->list = g_list_insert(list->list, (gpointer) object, position);
+ object_list_set_changed(list, TRUE);
+ object_list_callback_call(&list->add_cb, object);
+}
+
+void
+object_list_remove(ObjectList_t *list, Object_t *object)
+{
+ list->list = g_list_remove(list->list, (gpointer) object);
+ object_list_set_changed(list, TRUE);
+ object_list_callback_call(&list->remove_cb, object);
+ object_unref(object);
+}
+
+void
+object_list_remove_link(ObjectList_t *list, GList *link)
+{
+ list->list = g_list_remove_link(list->list, link);
+ object_list_set_changed(list, TRUE);
+ object_list_callback_call(&list->remove_cb, (Object_t*) link->data);
+}
+
+void
+object_list_update(ObjectList_t *list, Object_t *object)
+{
+ object_list_callback_call(&list->update_cb, object);
+}
+
+void
+object_list_draw(ObjectList_t *list, cairo_t *cr)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next)
+ object_draw((Object_t*) p->data, cr);
+}
+
+void
+object_list_draw_selected(ObjectList_t *list, cairo_t *cr)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_draw(obj, cr);
+ }
+}
+
+Object_t*
+object_list_find(ObjectList_t *list, gint x, gint y)
+{
+ Object_t *found = NULL;
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->class->point_is_on(obj, x, y))
+ found = obj;
+ }
+ return found;
+}
+
+Object_t*
+object_list_near_sash(ObjectList_t *list, gint x, gint y,
+ MoveSashFunc_t *sash_func)
+{
+ Object_t *found = NULL;
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected) {
+ MoveSashFunc_t func = obj->class->near_sash(obj, x, y);
+ if (func) {
+ found = obj;
+ *sash_func = func;
+ }
+ }
+ }
+ return found;
+}
+
+void
+object_list_remove_all(ObjectList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ object_list_callback_call(&list->remove_cb, obj);
+ object_unref(obj);
+ }
+ g_list_free(list->list);
+ list->list = NULL;
+ object_list_set_changed(list, TRUE);
+}
+
+void
+clear_paste_buffer(void)
+{
+ if (_paste_buffer)
+ object_list_remove_all(_paste_buffer);
+ else
+ _paste_buffer = make_object_list();
+}
+
+ObjectList_t*
+get_paste_buffer(void)
+{
+ return _paste_buffer;
+}
+
+gint
+object_list_cut(ObjectList_t *list)
+{
+ GList *p, *q;
+ gint count = 0;
+
+ clear_paste_buffer();
+ for (p = list->list; p; p = q) {
+ Object_t *obj = (Object_t*) p->data;
+ q = p->next;
+ if (obj->selected) {
+ if (obj->locked) {
+ do_object_locked_dialog();
+ } else {
+ object_list_append(_paste_buffer, obj);
+ object_list_remove_link(list, p);
+ count++;
+ }
+ }
+ }
+ object_list_set_changed(list, (count) ? TRUE : FALSE);
+ return count;
+}
+
+void
+object_list_copy_to_paste_buffer(ObjectList_t *list)
+{
+ GList *p;
+
+ clear_paste_buffer();
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_list_append(_paste_buffer, object_clone(obj));
+ }
+}
+
+void
+object_list_paste(ObjectList_t *list)
+{
+ object_list_append_list(list, _paste_buffer);
+}
+
+void
+object_list_delete_selected(ObjectList_t *list)
+{
+ GList *p, *q;
+ for (p = list->list; p; p = q) {
+ Object_t *obj = (Object_t*) p->data;
+ q = p->next;
+ if (obj->selected) {
+ if (obj->locked) {
+ do_object_locked_dialog();
+ } else {
+ object_list_remove_link(list, p);
+ object_unref(obj);
+ }
+ }
+ }
+}
+
+void
+object_list_edit_selected(ObjectList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected) {
+ object_edit(obj, TRUE);
+ break;
+ }
+ }
+}
+
+gint
+object_list_select_all(ObjectList_t *list)
+{
+ GList *p;
+ gint count = 0;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (!obj->selected) {
+ object_select(obj);
+ count++;
+ }
+ }
+ return count;
+}
+
+void
+object_list_select_next(ObjectList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected) {
+ object_unselect(obj);
+ p = (p->next) ? p->next : list->list;
+ object_select((Object_t*) p->data);
+ for (p = p->next; p; p = p->next) {
+ obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_unselect(obj);
+ }
+ break;
+ }
+ }
+}
+
+void object_list_select_prev(ObjectList_t *list)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected) {
+ GList *q = (p->prev) ? p->prev : g_list_last(list->list);
+ for (; p; p = p->next) {
+ obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_unselect(obj);
+ }
+ object_select((Object_t*) q->data);
+ break;
+ }
+ }
+}
+
+gint
+object_list_select_region(ObjectList_t *list, gint x, gint y, gint width,
+ gint height)
+{
+ GList *p;
+ gint count = 0;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ gint obj_x, obj_y, obj_width, obj_height;
+
+ object_get_dimensions(obj, &obj_x, &obj_y, &obj_width, &obj_height);
+ if (obj_x >= x && obj_x + obj_width <= x + width &&
+ obj_y >= y && obj_y + obj_height <= y + height) {
+ object_select(obj);
+ count++;
+ }
+ }
+ return count;
+}
+
+gint
+object_list_deselect_all(ObjectList_t *list, Object_t *exception)
+{
+ GList *p;
+ gint count = 0;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected && obj != exception) {
+ object_unselect(obj);
+ count++;
+ }
+ }
+ return count;
+}
+
+gint
+object_list_nr_selected(ObjectList_t *list)
+{
+ GList *p;
+ gint count = 0;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected)
+ count++;
+ }
+ return count;
+}
+
+void
+object_list_resize(ObjectList_t *list, gint percentage_x, gint percentage_y)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ object_resize(obj, percentage_x, percentage_y);
+ }
+}
+
+static void
+object_list_swap_prev(ObjectList_t *list, GList *p)
+{
+ gpointer swap = p->data;
+ p->data = p->prev->data;
+ p->prev->data = swap;
+ object_list_callback_call(&list->move_cb, (Object_t*) p->data);
+ object_list_callback_call(&list->move_cb, (Object_t*) p->prev->data);
+}
+
+static void
+object_list_swap_next(ObjectList_t *list, GList *p)
+{
+ gpointer swap = p->data;
+ p->data = p->next->data;
+ p->next->data = swap;
+ object_list_callback_call(&list->move_cb, (Object_t*) p->data);
+ object_list_callback_call(&list->move_cb, (Object_t*) p->next->data);
+}
+
+void
+object_list_move_selected(ObjectList_t *list, gint dx, gint dy)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_move(obj, dx, dy);
+ }
+}
+
+void
+object_list_move_up(ObjectList_t *list, Object_t *obj)
+{
+ GList *p = g_list_find(list->list, (gpointer) obj);
+ object_list_swap_prev(list, p);
+}
+
+void
+object_list_move_down(ObjectList_t *list, Object_t *obj)
+{
+ GList *p = g_list_find(list->list, (gpointer) obj);
+ object_list_swap_next(list, p);
+}
+
+void
+object_list_move_selected_up(ObjectList_t *list)
+{
+ GList *p;
+
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected && p->prev)
+ object_list_swap_prev(list, p);
+ }
+}
+
+void
+object_list_move_selected_down(ObjectList_t *list)
+{
+ GList *p;
+
+ for (p = g_list_last(list->list); p; p = p->prev) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected && p->next)
+ object_list_swap_next(list, p);
+ }
+}
+
+void
+object_list_move_to_front(ObjectList_t *list)
+{
+ GList *p, *q;
+ guint length = g_list_length(list->list);
+
+ for (p = list->list; length; p = q, length--) {
+ Object_t *obj = (Object_t*) p->data;
+ q = p->next;
+ if (obj->selected) {
+ object_list_remove_link(list, p);
+ object_list_append(list, obj);
+ }
+ }
+}
+
+void
+object_list_send_to_back(ObjectList_t *list)
+{
+ GList *p, *q;
+ guint length = g_list_length(list->list);
+
+ for (p = list->list; length; p = q, length--) {
+ Object_t *obj = (Object_t*) p->data;
+ q = p->next;
+ if (obj->selected) {
+ object_list_remove_link(list, p);
+ object_list_prepend(list, obj);
+ }
+ }
+}
+
+void
+object_list_move_sash_selected(ObjectList_t *list, gint dx, gint dy)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ if (obj->selected)
+ object_move_sash(obj, dx, dy);
+ }
+}
+
+static void
+write_xml_attrib(const gchar *attrib, const gchar *value,
+ const gchar *default_text, gpointer param,
+ OutputFunc_t output)
+{
+ if (*value) {
+ gchar *escaped_value = g_markup_escape_text(value, -1);
+ output(param, " %s=\"%s\"", attrib, escaped_value);
+ g_free(escaped_value);
+ } else if (*default_text) {
+ output(param, " %s", default_text);
+ }
+}
+
+void
+object_list_write_csim(ObjectList_t *list, gpointer param, OutputFunc_t output)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+
+ output(param, "<area shape=");
+ obj->class->write_csim(obj, param, output);
+
+ write_xml_attrib("alt", obj->comment, "", param, output);
+ write_xml_attrib("target", obj->target, "", param, output);
+ write_xml_attrib("onmouseover", obj->mouse_over, "", param, output);
+ write_xml_attrib("onmouseout", obj->mouse_out, "", param, output);
+ write_xml_attrib("onfocus", obj->focus, "", param, output);
+ write_xml_attrib("onblur", obj->blur, "", param, output);
+ write_xml_attrib("href", obj->url, " nohref=\"nohref\"", param, output);
+ output(param," />\n");
+ }
+}
+
+void
+object_list_write_cern(ObjectList_t *list, gpointer param, OutputFunc_t output)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+ obj->class->write_cern(obj, param, output);
+ output(param, " %s\n", obj->url);
+ }
+}
+
+void
+object_list_write_ncsa(ObjectList_t *list, gpointer param, OutputFunc_t output)
+{
+ GList *p;
+ for (p = list->list; p; p = p->next) {
+ Object_t *obj = (Object_t*) p->data;
+
+ if (*obj->comment)
+ output(param, "# %s\n", obj->comment);
+ obj->class->write_ncsa(obj, param, output);
+ output(param, "\n");
+ }
+}
diff --git a/plug-ins/imagemap/imap_object.h b/plug-ins/imagemap/imap_object.h
new file mode 100644
index 0000000..0aaf078
--- /dev/null
+++ b/plug-ins/imagemap/imap_object.h
@@ -0,0 +1,253 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_OBJECT_H
+#define _IMAP_OBJECT_H
+
+typedef struct Object_t Object_t;
+typedef struct ObjectClass_t ObjectClass_t;
+typedef struct ObjectList_t ObjectList_t;
+
+#include "imap_edit_area_info.h"
+#include "imap_menu_funcs.h"
+
+struct Object_t {
+ ObjectClass_t *class;
+ ObjectList_t *list;
+ gint refcount;
+ gboolean selected;
+ gboolean locked;
+ gchar *url;
+ gchar *target;
+ gchar *comment;
+ gchar *mouse_over;
+ gchar *mouse_out;
+ gchar *focus;
+ gchar *blur;
+};
+
+typedef void (*MoveSashFunc_t)(Object_t*, gint, gint);
+typedef void (*OutputFunc_t)(gpointer, const char*, ...) G_GNUC_PRINTF(2,3);
+
+struct AreaInfoDialog_t;
+
+struct ObjectClass_t {
+ const gchar *name;
+ AreaInfoDialog_t *info_dialog;
+
+ gboolean (*is_valid)(Object_t *obj);
+ void (*destruct)(Object_t *obj);
+ Object_t* (*clone)(Object_t *obj);
+ void (*assign)(Object_t *obj, Object_t *des);
+ void (*normalize)(Object_t *obj);
+ void (*draw)(Object_t *obj, cairo_t *cr);
+ void (*draw_sashes)(Object_t *obj, cairo_t *cr);
+ MoveSashFunc_t (*near_sash)(Object_t *obj, gint x, gint y);
+ gboolean (*point_is_on)(Object_t *obj, gint x, gint y);
+ void (*get_dimensions)(Object_t *obj, gint *x, gint *y, gint *width,
+ gint *height);
+ void (*resize)(Object_t *obj, gint percentage_x, gint percentage_y);
+ void (*move)(Object_t *obj, gint dx, gint dy);
+ gpointer (*create_info_widget)(GtkWidget *frame);
+ void (*update_info_widget)(Object_t *obj, gpointer data);
+ void (*fill_info_tab)(Object_t *obj, gpointer data);
+ void (*set_initial_focus)(Object_t *obj, gpointer data);
+ void (*update)(Object_t *obj, gpointer data);
+ void (*write_csim)(Object_t *obj, gpointer param, OutputFunc_t output);
+ void (*write_cern)(Object_t *obj, gpointer param, OutputFunc_t output);
+ void (*write_ncsa)(Object_t *obj, gpointer param, OutputFunc_t output);
+ void (*do_popup)(Object_t *obj, GdkEventButton *event);
+
+ const gchar* (*get_stock_icon_name)(void);
+};
+
+Object_t *object_ref(Object_t *obj);
+void object_unref(Object_t *obj);
+Object_t* object_init(Object_t *obj, ObjectClass_t *class);
+Object_t* object_clone(Object_t *obj);
+Object_t* object_assign(Object_t *src, Object_t *des);
+void object_draw(Object_t *obj, cairo_t *cr);
+void object_edit(Object_t *obj, gboolean add);
+void object_select(Object_t *obj);
+void object_unselect(Object_t *obj);
+void object_move(Object_t *obj, gint dx, gint dy);
+void object_move_sash(Object_t *obj, gint dx, gint dy);
+void object_remove(Object_t *obj);
+void object_lock(Object_t *obj);
+void object_unlock(Object_t *obj);
+void object_set_url(Object_t *obj, const gchar *url);
+void object_set_target(Object_t *obj, const gchar *target);
+void object_set_comment(Object_t *obj, const gchar *comment);
+void object_set_mouse_over(Object_t *obj, const gchar *mouse_over);
+void object_set_mouse_out(Object_t *obj, const gchar *mouse_out);
+void object_set_focus(Object_t *obj, const gchar *focus);
+void object_set_blur(Object_t *obj, const gchar *blur);
+gint object_get_position_in_list(Object_t *obj);
+
+void object_emit_changed_signal(Object_t *obj);
+void object_emit_geometry_signal(Object_t *obj);
+void object_emit_update_signal(Object_t *obj);
+
+#define object_is_valid(obj) \
+ ((obj)->class->is_valid(obj))
+
+#define object_get_dimensions(obj, x, y, width, height) \
+ ((obj)->class->get_dimensions((obj), (x), (y), (width), (height)))
+
+#define object_normalize(obj) \
+ ((obj)->class->normalize(obj))
+
+#define object_resize(obj, per_x, per_y) \
+ ((obj)->class->resize((obj), (per_x), (per_y)))
+
+#define object_update(obj, data) \
+ ((obj)->class->update((obj), (data)))
+
+#define object_update_info_widget(obj, data) \
+ ((obj)->class->update_info_widget((obj), (data)))
+
+#define object_fill_info_tab(obj, data) \
+ ((obj)->class->fill_info_tab((obj), (data)))
+
+#define object_get_stock_icon_name(obj) \
+ ((obj)->class->get_stock_icon_name())
+
+typedef struct {
+ Object_t *obj;
+ gboolean (*finish)(Object_t *obj, gint x, gint y);
+ gboolean (*cancel)(GdkEventButton *event, Object_t *obj);
+ Object_t* (*create_object)(gint x, gint y);
+ void (*set_xy)(Object_t *obj, guint state, gint x, gint y);
+} ObjectFactory_t;
+
+gboolean object_on_button_press(GtkWidget *widget, GdkEventButton *event,
+ gpointer data);
+
+typedef struct {
+ GList *list;
+} ObjectListCallback_t;
+
+struct ObjectList_t {
+ GList *list;
+ gboolean changed;
+ ObjectListCallback_t changed_cb;
+ ObjectListCallback_t update_cb;
+ ObjectListCallback_t add_cb;
+ ObjectListCallback_t remove_cb;
+ ObjectListCallback_t select_cb;
+ ObjectListCallback_t move_cb;
+ ObjectListCallback_t geometry_cb;
+};
+
+ObjectList_t *make_object_list (void);
+void object_list_destruct(ObjectList_t *list);
+ObjectList_t *object_list_copy(ObjectList_t *des, ObjectList_t *src);
+ObjectList_t *object_list_append_list(ObjectList_t *des, ObjectList_t *src);
+
+void object_list_append(ObjectList_t *list, Object_t *object);
+void object_list_prepend(ObjectList_t *list, Object_t *object);
+void object_list_insert(ObjectList_t *list, gint position, Object_t *object);
+void object_list_remove(ObjectList_t *list, Object_t *object);
+void object_list_remove_link(ObjectList_t *list, GList *link);
+void object_list_update(ObjectList_t *list, Object_t *object);
+void object_list_draw(ObjectList_t *list, cairo_t *cr);
+void object_list_draw_selected(ObjectList_t *list, cairo_t *cr);
+Object_t *object_list_find(ObjectList_t *list, gint x, gint y);
+Object_t *object_list_near_sash(ObjectList_t *list, gint x, gint y,
+ MoveSashFunc_t *sash_func);
+
+gint object_list_cut(ObjectList_t *list);
+void object_list_copy_to_paste_buffer(ObjectList_t *list);
+void object_list_paste(ObjectList_t *list);
+
+void object_list_remove_all(ObjectList_t *list);
+void object_list_delete_selected(ObjectList_t *list);
+void object_list_edit_selected(ObjectList_t *list);
+gint object_list_select_all(ObjectList_t *list);
+void object_list_select_next(ObjectList_t *list);
+void object_list_select_prev(ObjectList_t *list);
+gint object_list_select_region(ObjectList_t *list, gint x, gint y, gint width,
+ gint height);
+gint object_list_deselect_all(ObjectList_t *list, Object_t *exception);
+gint object_list_nr_selected(ObjectList_t *list);
+void object_list_resize(ObjectList_t *list, gint percentage_x,
+ gint percentage_y);
+void object_list_move_selected(ObjectList_t *list, gint dx, gint dy);
+void object_list_move_up(ObjectList_t *list, Object_t *obj);
+void object_list_move_down(ObjectList_t *list, Object_t *obj);
+void object_list_move_selected_up(ObjectList_t *list);
+void object_list_move_selected_down(ObjectList_t *list);
+void object_list_move_to_front(ObjectList_t *list);
+void object_list_send_to_back(ObjectList_t *list);
+void object_list_move_sash_selected(ObjectList_t *list, gint dx, gint dy);
+
+void object_list_write_csim(ObjectList_t *list, gpointer param,
+ OutputFunc_t output);
+void object_list_write_cern(ObjectList_t *list, gpointer param,
+ OutputFunc_t output);
+void object_list_write_ncsa(ObjectList_t *list, gpointer param,
+ OutputFunc_t output);
+
+typedef void (*ObjectListCallbackFunc_t)(Object_t*, gpointer);
+
+gpointer object_list_add_changed_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func,
+ gpointer data);
+gpointer object_list_add_update_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func,
+ gpointer data);
+gpointer object_list_add_add_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func, gpointer data);
+gpointer object_list_add_remove_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func,
+ gpointer data);
+gpointer object_list_add_select_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func,
+ gpointer data);
+gpointer object_list_add_move_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func, gpointer data);
+gpointer object_list_add_geometry_cb(ObjectList_t *list,
+ ObjectListCallbackFunc_t func,
+ gpointer data);
+
+void object_list_remove_add_cb(ObjectList_t *list, gpointer id);
+void object_list_remove_select_cb(ObjectList_t *list, gpointer id);
+void object_list_remove_remove_cb(ObjectList_t *list, gpointer id);
+void object_list_remove_move_cb(ObjectList_t *list, gpointer id);
+void object_list_remove_geometry_cb(ObjectList_t *list, gpointer id);
+
+#define object_list_clear_changed(list) ((list)->changed = FALSE)
+#define object_list_set_changed(list, ischanged) \
+ ((list)->changed = (ischanged))
+#define object_list_get_changed(list) ((list)->changed)
+
+void clear_paste_buffer(void);
+gpointer paste_buffer_add_add_cb(ObjectListCallbackFunc_t func, gpointer data);
+gpointer paste_buffer_add_remove_cb(ObjectListCallbackFunc_t func,
+ gpointer data);
+ObjectList_t *get_paste_buffer(void);
+
+void do_object_locked_dialog(void);
+
+#endif /* _IMAP_OBJECT_H */
+
+
diff --git a/plug-ins/imagemap/imap_object_popup.c b/plug-ins/imagemap/imap_object_popup.c
new file mode 100644
index 0000000..63b195f
--- /dev/null
+++ b/plug-ins/imagemap/imap_object_popup.c
@@ -0,0 +1,60 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_commands.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_object_popup.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+void
+object_handle_popup(ObjectPopup_t *popup, Object_t *obj, GdkEventButton *event)
+{
+ /* int position = object_get_position_in_list(obj) + 1; */
+
+#ifdef _TEMP_
+ gtk_widget_set_sensitive(popup->up, (position > 1) ? TRUE : FALSE);
+ gtk_widget_set_sensitive(popup->down,
+ (position < g_list_length(obj->list->list))
+ ? TRUE : FALSE);
+#endif
+ gtk_menu_popup(GTK_MENU(popup->menu), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+}
+
+void
+object_do_popup(Object_t *obj, GdkEventButton *event)
+{
+ static ObjectPopup_t *popup;
+
+ if (!popup)
+ {
+ popup = g_new (ObjectPopup_t, 1);
+ popup->menu = menu_get_widget ("/ObjectPopupMenu");
+ }
+ object_handle_popup (popup, obj, event);
+}
diff --git a/plug-ins/imagemap/imap_object_popup.h b/plug-ins/imagemap/imap_object_popup.h
new file mode 100644
index 0000000..bc7afee
--- /dev/null
+++ b/plug-ins/imagemap/imap_object_popup.h
@@ -0,0 +1,39 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_OBJECT_POPUP_H
+#define _IMAP_OBJECT_POPUP_H
+
+#include "imap_object.h"
+
+typedef struct {
+ GtkWidget *menu;
+ GtkWidget *up;
+ GtkWidget *down;
+ Object_t *obj;
+} ObjectPopup_t;
+
+void object_handle_popup(ObjectPopup_t *popup, Object_t *obj,
+ GdkEventButton *event);
+void object_do_popup(Object_t *obj, GdkEventButton *event);
+
+#endif /* _IMAP_OBJECT_POPUP_H */
diff --git a/plug-ins/imagemap/imap_polygon.c b/plug-ins/imagemap/imap_polygon.c
new file mode 100644
index 0000000..6428cd3
--- /dev/null
+++ b/plug-ins/imagemap/imap_polygon.c
@@ -0,0 +1,854 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <stdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "imap_commands.h"
+#include "imap_main.h"
+#include "imap_misc.h"
+#include "imap_menu.h"
+#include "imap_object_popup.h"
+#include "imap_polygon.h"
+#include "imap_stock.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+#define MAX_POLYGON_POINTS 99
+
+static gboolean polygon_is_valid(Object_t *obj);
+static void polygon_destruct(Object_t *obj);
+static Object_t *polygon_clone(Object_t *obj);
+static void polygon_assign(Object_t *obj, Object_t *des);
+static void polygon_draw(Object_t* obj, cairo_t *cr);
+static void polygon_draw_sashes(Object_t* obj, cairo_t *cr);
+static MoveSashFunc_t polygon_near_sash(Object_t *obj, gint x, gint y);
+static gboolean polygon_point_is_on(Object_t *obj, gint x, gint y);
+static void polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height);
+static void polygon_resize(Object_t *obj, gint percentage_x,
+ gint percentage_y);
+static void polygon_move(Object_t *obj, gint dx, gint dy);
+static gpointer polygon_create_info_widget(GtkWidget *frame);
+static void polygon_update_info_widget(Object_t *obj, gpointer data);
+static void polygon_fill_info_tab(Object_t *obj, gpointer data);
+static void polygon_set_initial_focus(Object_t *obj, gpointer data);
+static void polygon_update(Object_t* obj, gpointer data);
+static void polygon_write_csim(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static void polygon_write_cern(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static void polygon_write_ncsa(Object_t* obj, gpointer param,
+ OutputFunc_t output);
+static void polygon_do_popup(Object_t *obj, GdkEventButton *event);
+static const gchar* polygon_get_stock_icon_name(void);
+
+static ObjectClass_t polygon_class = {
+ N_("_Polygon"),
+ NULL, /* info_dialog */
+
+ polygon_is_valid,
+ polygon_destruct,
+ polygon_clone,
+ polygon_assign,
+ NULL, /* polygon_normalize */
+ polygon_draw,
+ polygon_draw_sashes,
+ polygon_near_sash,
+ polygon_point_is_on,
+ polygon_get_dimensions,
+ polygon_resize,
+ polygon_move,
+ polygon_create_info_widget,
+ polygon_update_info_widget,
+ polygon_fill_info_tab,
+ polygon_set_initial_focus,
+ polygon_update,
+ polygon_write_csim,
+ polygon_write_cern,
+ polygon_write_ncsa,
+ polygon_do_popup,
+ polygon_get_stock_icon_name
+};
+
+Object_t*
+create_polygon(GList *points)
+{
+ Polygon_t *polygon = g_new(Polygon_t, 1);
+ polygon->points = points;
+ return object_init(&polygon->obj, &polygon_class);
+}
+
+static void
+polygon_free_list (Polygon_t *polygon)
+{
+ g_list_free_full (polygon->points, (GDestroyNotify) g_free);
+ polygon->points = NULL;
+}
+
+static void
+polygon_destruct(Object_t *obj)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ polygon_free_list(polygon);
+}
+
+static gboolean
+polygon_is_valid(Object_t *obj)
+{
+ return g_list_length(ObjectToPolygon(obj)->points) > 2;
+}
+
+static Object_t*
+polygon_clone(Object_t *obj)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ Polygon_t *clone = g_new(Polygon_t, 1);
+ GList *p;
+
+ clone->points = NULL;
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ polygon_append_point(clone, point->x, point->y);
+ }
+ return &clone->obj;
+}
+
+static void
+polygon_assign(Object_t *obj, Object_t *des)
+{
+ Polygon_t *src_polygon = ObjectToPolygon(obj);
+ Polygon_t *des_polygon = ObjectToPolygon(des);
+ GList *p;
+
+ polygon_free_list(des_polygon);
+ for (p = src_polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ polygon_append_point(des_polygon, point->x, point->y);
+ }
+}
+
+static void
+polygon_draw(Object_t *obj, cairo_t *cr)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ draw_polygon(cr, polygon->points);
+}
+
+static void
+polygon_draw_sashes(Object_t *obj, cairo_t *cr)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ draw_sash(cr, point->x, point->y);
+ }
+}
+
+static GdkPoint *_sash_point;
+static gint _sash_index;
+
+static void
+move_sash(Object_t *obj, gint dx, gint dy)
+{
+ _sash_point->x += dx;
+ _sash_point->y += dy;
+}
+
+static MoveSashFunc_t
+polygon_near_sash(Object_t *obj, gint x, gint y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+
+ _sash_index = 0;
+ for (p = polygon->points; p; p = p->next, _sash_index++) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ if (near_sash(point->x, point->y, x, y)) {
+ _sash_point = point;
+ return move_sash;
+ }
+ }
+ return NULL;
+}
+
+static gboolean
+right_intersect(GdkPoint *p1, GdkPoint *p2, gint x, gint y)
+{
+ gint dx = p2->x - p1->x;
+ gint dy = p2->y - p1->y;
+
+ if ((dy > 0 && y > p1->y && y < p2->y) ||
+ (dy < 0 && y > p2->y && y < p1->y)) {
+ gint sx = p1->x + (y - p1->y) * dx / dy;
+ return sx > x;
+ }
+ return FALSE;
+}
+
+static gboolean
+polygon_point_is_on(Object_t *obj, gint x, gint y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ int count = 0;
+ GdkPoint *first, *prev;
+
+ p = polygon->points;
+ first = prev = (GdkPoint*) p->data;
+ p = p->next;
+
+ for (; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ if (right_intersect(prev, point, x, y))
+ count++;
+ prev = point;
+ }
+ if (right_intersect(prev, first, x, y))
+ count++;
+
+ return count % 2;
+}
+
+static void
+polygon_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ gint min_x = G_MAXINT, min_y = G_MAXINT;
+ gint max_x = G_MININT, max_y = G_MININT;
+ GList *p;
+
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ if (point->x < min_x)
+ min_x = point->x;
+ if (point->x > max_x)
+ max_x = point->x;
+ if (point->y < min_y)
+ min_y = point->y;
+ if (point->y > max_y)
+ max_y = point->y;
+ }
+ *x = min_x;
+ *y = min_y;
+ *width = max_x - min_x;
+ *height = max_y - min_y;
+}
+
+static void
+polygon_resize(Object_t *obj, gint percentage_x, gint percentage_y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ point->x = point->x * percentage_x / 100;
+ point->y = point->y * percentage_y / 100;
+ }
+}
+
+static void
+polygon_move(Object_t *obj, gint dx, gint dy)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ point->x += dx;
+ point->y += dy;
+ }
+}
+
+typedef struct {
+ Object_t *obj;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+ GtkWidget *x;
+ GtkWidget *y;
+ GtkWidget *update;
+ GtkWidget *insert;
+ GtkWidget *append;
+ GtkWidget *remove;
+ gint selected_row;
+ guint timeout;
+} PolygonProperties_t;
+
+static void
+select_row_cb(GtkTreeSelection *selection, PolygonProperties_t *data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ GdkPoint *point;
+
+ gtk_tree_model_get (model, &iter, 0, &point, -1);
+
+ _sash_point = point;
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->x), point->x);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->y), point->y);
+ }
+}
+
+static void
+update_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL(data->store);
+
+ if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
+ GdkPoint *point;
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
+
+ gtk_tree_model_get (model, &iter, 0, &point, -1);
+ point->x = x;
+ point->y = y;
+ gtk_list_store_set (data->store, &iter, 0, point, -1);
+ }
+}
+
+static void
+set_buttons_sensitivity(PolygonProperties_t *data)
+{
+ gint rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(data->store),
+ NULL);
+ gtk_widget_set_sensitive(data->insert, rows != MAX_POLYGON_POINTS);
+ gtk_widget_set_sensitive(data->append, rows != MAX_POLYGON_POINTS);
+ gtk_widget_set_sensitive(data->remove, rows > 2);
+}
+
+static void
+insert_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL(data->store);
+
+ if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
+ Polygon_t *polygon = ObjectToPolygon(data->obj);
+ GdkPoint *point;
+ GList *here;
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
+
+ gtk_tree_model_get (model, &iter, 0, &point, -1);
+ here = g_list_find(polygon->points, point);
+ polygon->points = g_list_insert_before(polygon->points, here,
+ new_point(x, y));
+ polygon_fill_info_tab(data->obj, data);
+ }
+}
+
+static void
+append_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
+{
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->x));
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(data->y));
+
+ polygon_append_point(ObjectToPolygon(data->obj), x, y);
+ polygon_fill_info_tab(data->obj, data);
+}
+
+static void
+remove_button_clicked(GtkWidget *widget, PolygonProperties_t *data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL(data->store);
+
+ if (gtk_tree_selection_get_selected (data->selection, &model, &iter)) {
+ Polygon_t *polygon = ObjectToPolygon(data->obj);
+ GdkPoint *point;
+
+ gtk_tree_model_get (model, &iter, 0, &point, -1);
+ polygon->points = g_list_remove(polygon->points, point);
+ g_free(point);
+
+ polygon_fill_info_tab(data->obj, data);
+ }
+}
+
+static void
+x_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((PolygonProperties_t*) data)->obj;
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ _sash_point->x = x;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+y_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((PolygonProperties_t*) data)->obj;
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ _sash_point->y = y;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+render_x(GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ GdkPoint *point;
+ gchar scratch[16];
+
+ gtk_tree_model_get(tree_model, iter, 0, &point, -1);
+ sprintf(scratch, "%d", point->x);
+ g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
+}
+
+static void
+render_y(GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ GdkPoint *point;
+ gchar scratch[16];
+
+ gtk_tree_model_get(tree_model, iter, 0, &point, -1);
+ sprintf(scratch, "%d", point->y);
+ g_object_set(cell, "text", scratch, "xalign", 1.0, NULL);
+}
+
+static gpointer
+polygon_create_info_widget(GtkWidget *frame)
+{
+ PolygonProperties_t *props = g_new(PolygonProperties_t, 1);
+ GtkWidget *hbox, *swin, *table, *label;
+ GtkWidget *view;
+ gint max_width = get_image_width();
+ gint max_height = get_image_height();
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+
+ swin = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(swin),
+ GTK_SHADOW_IN);
+ gtk_box_pack_start(GTK_BOX(hbox), swin, FALSE, FALSE, FALSE);
+ gtk_widget_show(swin);
+
+ props->store = gtk_list_store_new (1, G_TYPE_POINTER);
+ view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (props->store));
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
+ g_object_unref (props->store);
+ gtk_widget_show (view);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("x (pixels)"),
+ renderer,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func(column, renderer,
+ render_x, props, NULL);
+ gtk_tree_view_column_set_alignment(column, 0.5);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("y (pixels)"),
+ renderer,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func(column, renderer,
+ render_y, props, NULL);
+ gtk_tree_view_column_set_alignment(column, 0.5);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
+
+ gtk_container_add (GTK_CONTAINER (swin), view);
+
+ table = gtk_table_new(6, 3, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, FALSE);
+ gtk_widget_show(table);
+
+ label = create_label_in_table(table, 0, 0, "_x:");
+ props->x = create_spin_button_in_table(table, label, 0, 1, 1, 0,
+ max_width - 1);
+ g_signal_connect(props->x, "changed",
+ G_CALLBACK(x_changed_cb), (gpointer) props);
+ gtk_widget_set_size_request(props->x, 64, -1);
+ create_label_in_table(table, 0, 2, _("pixels"));
+
+ label = create_label_in_table(table, 1, 0, "_y:");
+ props->y = create_spin_button_in_table(table, label, 1, 1, 1, 0,
+ max_height - 1);
+ g_signal_connect(props->y, "changed",
+ G_CALLBACK(y_changed_cb), (gpointer) props);
+ gtk_widget_set_size_request(props->y, 64, -1);
+ create_label_in_table(table, 1, 2, _("pixels"));
+
+ props->update = gtk_button_new_with_mnemonic(_("_Update"));
+ g_signal_connect(props->update, "clicked",
+ G_CALLBACK(update_button_clicked), props);
+ gtk_table_attach_defaults(GTK_TABLE(table), props->update, 1, 2, 2, 3);
+ gtk_widget_show(props->update);
+
+ props->insert = gtk_button_new_with_mnemonic(_("_Insert"));
+ g_signal_connect(props->insert, "clicked",
+ G_CALLBACK(insert_button_clicked), props);
+ gtk_table_attach_defaults(GTK_TABLE(table), props->insert, 1, 2, 3, 4);
+ gtk_widget_show(props->insert);
+
+ props->append = gtk_button_new_with_mnemonic(_("A_ppend"));
+ g_signal_connect(props->append, "clicked",
+ G_CALLBACK(append_button_clicked), props);
+ gtk_table_attach_defaults(GTK_TABLE(table), props->append, 1, 2, 4, 5);
+ gtk_widget_show(props->append);
+
+ props->remove = gtk_button_new_with_mnemonic(_("_Remove"));
+ g_signal_connect(props->remove, "clicked",
+ G_CALLBACK(remove_button_clicked), props);
+ gtk_table_attach_defaults(GTK_TABLE(table), props->remove, 1, 2, 5, 6);
+ gtk_widget_show(props->remove);
+
+ props->timeout = 0;
+
+ props->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (view));
+ gtk_tree_selection_set_mode(props->selection, GTK_SELECTION_SINGLE);
+ g_signal_connect (props->selection, "changed",
+ G_CALLBACK (select_row_cb), props);
+
+ return props;
+}
+
+static gboolean
+update_timeout(gpointer data)
+{
+ PolygonProperties_t *props = (PolygonProperties_t*) data;
+ polygon_fill_info_tab(props->obj, data);
+ return FALSE;
+}
+
+static void
+polygon_update_info_widget(Object_t *obj, gpointer data)
+{
+ PolygonProperties_t *props = (PolygonProperties_t*) data;
+ GtkTreeIter iter;
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), _sash_point->x);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), _sash_point->y);
+
+ if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
+ NULL, _sash_index)) {
+ gtk_tree_selection_select_iter(props->selection, &iter);
+ }
+
+ if (props->timeout)
+ g_source_remove(props->timeout);
+ props->timeout = g_timeout_add(1000, update_timeout, data);
+}
+
+static void
+polygon_fill_info_tab(Object_t *obj, gpointer data)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ PolygonProperties_t *props = (PolygonProperties_t*) data;
+ GtkTreeIter iter;
+ GList *p;
+
+ props->obj = obj;
+
+ gtk_list_store_clear(props->store);
+
+ for (p = polygon->points; p; p = p->next) {
+ gtk_list_store_append(props->store, &iter);
+ gtk_list_store_set(props->store, &iter, 0, p->data, -1);
+ }
+
+ if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(props->store), &iter,
+ NULL, _sash_index)) {
+ gtk_tree_selection_select_iter(props->selection, &iter);
+ }
+ set_buttons_sensitivity(props);
+}
+
+static void
+polygon_set_initial_focus(Object_t *obj, gpointer data)
+{
+ PolygonProperties_t *props = (PolygonProperties_t*) data;
+ gtk_widget_grab_focus(props->x);
+}
+
+static void
+polygon_update(Object_t* obj, gpointer data)
+{
+ /* Nothing to be done! */
+}
+
+static void
+polygon_write_csim(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+
+ output(param, "\"poly\" coords=\"");
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ output(param, "%d,%d", point->x, point->y);
+ output(param, "%c", (p->next) ? ',' : '"');
+ }
+}
+
+static void
+polygon_write_cern(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ GdkPoint *first = (GdkPoint*) polygon->points->data;
+
+ output(param, "poly ");
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ output(param, "(%d,%d) ", point->x, point->y);
+ }
+ output(param, "(%d,%d)", first->x, first->y);
+}
+
+static void
+polygon_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p;
+ GdkPoint *first = (GdkPoint*) polygon->points->data;
+
+ output(param, "poly %s", obj->url);
+ for (p = polygon->points; p; p = p->next) {
+ GdkPoint *point = (GdkPoint*) p->data;
+ output(param, " %d,%d", point->x, point->y);
+ }
+ output(param, " %d,%d", first->x, first->y);
+}
+
+static Object_t *_current_obj;
+static gboolean _insert_edge;
+static gint _insert_x;
+static gint _insert_y;
+
+void
+polygon_insert_point(void)
+{
+ Command_t *command = insert_point_command_new (_current_obj, _insert_x,
+ _insert_y, _insert_edge);
+ command_execute (command);
+}
+
+void
+polygon_delete_point(void)
+{
+ Command_t *command = delete_point_command_new(_current_obj, _sash_point);
+ command_execute (command);
+}
+
+static gboolean
+point_near_edge(GdkPoint *first, GdkPoint *second, gint x, gint y)
+{
+ gint den, nom;
+ gdouble u;
+
+ den = (first->x - x) * (first->x - second->x) +
+ (first->y - y) * (first->y - second->y);
+ nom = (second->x - first->x) * (second->x - first->x) +
+ (second->y - first->y) * (second->y - first->y);
+ u = (gdouble) den / nom;
+ if (u >= 0.0 && u <= 1.0) {
+ gint sx = first->x + (gint) (u * (second->x - first->x)) - x;
+ gint sy = first->y + (gint) (u * (second->y - first->y)) - y;
+ return sx * sx + sy * sy <= 25; /* Fix me! */
+ }
+ return FALSE;
+}
+
+static gint
+polygon_near_edge(Object_t *obj, gint x, gint y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *p = polygon->points;
+ GdkPoint *first = (GdkPoint*) p->data;
+ GdkPoint *prev = first;
+ gint n = 1;
+
+ for (p = p->next; p; p = p->next, n++) {
+ GdkPoint *next = (GdkPoint*) p->data;
+ if (point_near_edge(prev, next, x, y))
+ return n;
+ prev = next;
+ }
+ return (point_near_edge(prev, first, x, y)) ? n + 1 : 0;
+}
+
+static void
+polygon_handle_popup (GdkEventButton *event, gboolean near_sash,
+ gboolean near_edge)
+{
+ GtkWidget *popup = menu_get_widget ("/PolygonPopupMenu");
+ GtkWidget *delete = menu_get_widget ("/PolygonPopupMenu/DeletePoint");
+ GtkWidget *insert = menu_get_widget ("/PolygonPopupMenu/InsertPoint");
+
+ gtk_widget_set_sensitive (delete, near_sash);
+ gtk_widget_set_sensitive (insert, near_edge);
+
+ gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
+ event->button, event->time);
+}
+
+static void
+polygon_do_popup(Object_t *obj, GdkEventButton *event)
+{
+ gint x = get_real_coord ((gint) event->x);
+ gint y = get_real_coord ((gint) event->y);
+
+ _current_obj = obj;
+
+ if (polygon_near_sash (obj, x, y))
+ {
+ polygon_handle_popup (event, TRUE, FALSE);
+ }
+ else
+ {
+ _insert_edge = polygon_near_edge (obj, x, y);
+ if (_insert_edge)
+ {
+ _insert_x = x;
+ _insert_y = y;
+
+ polygon_handle_popup (event, FALSE, TRUE);
+ }
+ else {
+ object_do_popup (obj, event);
+ }
+ }
+}
+
+static const gchar*
+polygon_get_stock_icon_name(void)
+{
+ return IMAP_STOCK_POLYGON;
+}
+
+static GList *_prev_link;
+
+static gboolean
+polygon_factory_finish(Object_t *obj, gint x, gint y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GdkPoint *prev_point = (GdkPoint*) _prev_link->data;
+
+ if (x == prev_point->x && y == prev_point->y) {
+ polygon_remove_last_point(polygon);
+ return TRUE;
+ } else {
+ polygon_append_point(polygon, x, y);
+ _prev_link = _prev_link->next;
+ }
+ return FALSE;
+}
+
+static gboolean
+polygon_factory_cancel(GdkEventButton *event, Object_t *obj)
+{
+ if (event->state & GDK_SHIFT_MASK) {
+ return TRUE;
+ } else {
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *link = _prev_link;
+
+ _prev_link = _prev_link->prev;
+ g_free((GdkPoint*) link->data);
+ polygon->points = g_list_remove_link(polygon->points, link);
+ }
+ return _prev_link == NULL;
+}
+
+static Object_t*
+polygon_factory_create_object(gint x, gint y)
+{
+ GList *points;
+
+ points = _prev_link = g_list_append(NULL, new_point(x, y));
+ points = g_list_append(points, new_point(x, y));
+
+ return create_polygon(points);
+}
+
+static void
+polygon_factory_set_xy(Object_t *obj, guint state, gint x, gint y)
+{
+ Polygon_t *polygon = ObjectToPolygon(obj);
+ GList *last = g_list_last(polygon->points);
+ GdkPoint *point = (GdkPoint*) last->data;
+ GdkPoint *prev = (GdkPoint*) last->prev->data;
+
+ point->x = x;
+ point->y = y;
+
+ main_set_dimension(x - prev->x, y - prev->y);
+}
+
+static ObjectFactory_t polygon_factory = {
+ NULL, /* Object pointer */
+ polygon_factory_finish,
+ polygon_factory_cancel,
+ polygon_factory_create_object,
+ polygon_factory_set_xy
+};
+
+ObjectFactory_t*
+get_polygon_factory(guint state)
+{
+ return &polygon_factory;
+}
+
+void
+polygon_remove_last_point(Polygon_t *polygon)
+{
+ GList *last = g_list_last(polygon->points);
+ g_free((GdkPoint*) last->data);
+ polygon->points = g_list_remove_link(polygon->points, last);
+}
+
+GdkPoint*
+new_point(gint x, gint y)
+{
+ GdkPoint *point = g_new(GdkPoint, 1);
+ point->x = x;
+ point->y = y;
+ return point;
+}
+
+void
+polygon_append_point(Polygon_t *polygon, gint x, gint y)
+{
+ polygon->points = g_list_append(polygon->points, new_point(x, y));
+}
diff --git a/plug-ins/imagemap/imap_polygon.h b/plug-ins/imagemap/imap_polygon.h
new file mode 100644
index 0000000..13ce29e
--- /dev/null
+++ b/plug-ins/imagemap/imap_polygon.h
@@ -0,0 +1,45 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_POLYGON_H
+#define _IMAP_POLYGON_H
+
+#include "imap_object.h"
+
+typedef struct {
+ Object_t obj;
+ GList *points;
+} Polygon_t;
+
+#define ObjectToPolygon(obj) ((Polygon_t*) (obj))
+
+Object_t *create_polygon (GList *points);
+ObjectFactory_t *get_polygon_factory (guint state);
+
+void polygon_insert_point (void);
+void polygon_delete_point (void);
+
+void polygon_remove_last_point (Polygon_t *polygon);
+void polygon_append_point (Polygon_t *polygon, gint x, gint y);
+GdkPoint *new_point (gint x, gint y);
+
+#endif /* _IMAP_POLYGON_H */
diff --git a/plug-ins/imagemap/imap_preferences.c b/plug-ins/imagemap/imap_preferences.c
new file mode 100644
index 0000000..218aa46
--- /dev/null
+++ b/plug-ins/imagemap/imap_preferences.c
@@ -0,0 +1,527 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <glib/gstdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "imap_command.h"
+#include "imap_file.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_misc.h"
+#include "imap_mru.h"
+#include "imap_preferences.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+typedef struct {
+ DefaultDialog_t *dialog;
+ GtkWidget *notebook;
+ GtkWidget *ncsa;
+ GtkWidget *cern;
+ GtkWidget *csim;
+ GtkWidget *prompt_for_area_info;
+ GtkWidget *require_default_url;
+ GtkWidget *show_area_handle;
+ GtkWidget *keep_circles_round;
+ GtkWidget *show_url_tip;
+ GtkWidget *use_doublesized;
+
+ GtkWidget *undo_levels;
+ GtkWidget *mru_size;
+
+ GtkWidget *normal_fg;
+ GtkWidget *normal_bg;
+ GtkWidget *selected_fg;
+ GtkWidget *selected_bg;
+ GtkWidget *interactive_fg;
+ GtkWidget *interactive_bg;
+
+ GtkWidget *threshold;
+ GtkWidget *auto_convert;
+
+ PreferencesData_t *old_data;
+} PreferencesDialog_t;
+
+static void get_button_colors (PreferencesDialog_t *dialog,
+ ColorSelData_t *colors);
+
+static gint
+parse_map_type(void)
+{
+ char *token = strtok(NULL, " )");
+ if (!strcmp(token, "ncsa"))
+ return NCSA;
+ else if (!strcmp(token, "cern"))
+ return CERN;
+ return CSIM;
+}
+
+static gint
+parse_yes_no(void)
+{
+ char *token = strtok(NULL, " )");
+ return (gint) strcmp(token, "no");
+}
+
+static gint
+parse_int(void)
+{
+ char *token = strtok(NULL, " )");
+ return (gint) atoi(token);
+}
+
+static void
+parse_color(GdkColor *gdk_color)
+{
+ gdk_color->red = (guint16) parse_int();
+ gdk_color->green = (guint16) parse_int();
+ gdk_color->blue = (guint16) parse_int();
+}
+
+static void
+parse_mru_entry(void)
+{
+ char *filename = strtok(NULL, " )");
+ mru_add(get_mru(), filename);
+}
+
+static void
+parse_line(PreferencesData_t *data, char *line)
+{
+ char *token;
+ ColorSelData_t *colors = &data->colors;
+
+ line++; /* Skip '(' */
+ token = strtok(line, " ");
+
+ if (!strcmp(token, "default-map-type")) {
+ data->default_map_type = parse_map_type();
+ }else if (!strcmp(token, "prompt-for-area-info")) {
+ data->prompt_for_area_info = parse_yes_no();
+ } else if (!strcmp(token, "require-default-url")) {
+ data->require_default_url = parse_yes_no();
+ } else if (!strcmp(token, "show-area-handle")) {
+ data->show_area_handle = parse_yes_no();
+ } else if (!strcmp(token, "keep-circles-round")) {
+ data->keep_circles_round = parse_yes_no();
+ } else if (!strcmp(token, "show-url-tip")) {
+ data->show_url_tip = parse_yes_no();
+ } else if (!strcmp(token, "use-doublesized")) {
+ data->use_doublesized = parse_yes_no();
+ } else if (!strcmp(token, "mru-size")) {
+ data->mru_size = parse_int();
+ if (data->mru_size < 1)
+ data->mru_size = 1;
+ } else if (!strcmp(token, "undo-levels")) {
+ data->undo_levels = parse_int();
+ if (data->undo_levels < 1)
+ data->undo_levels = 1;
+ } else if (!strcmp(token, "normal-fg-color")) {
+ parse_color(&colors->normal_fg);
+ } else if (!strcmp(token, "normal-bg-color")) {
+ parse_color(&colors->normal_bg);
+ } else if (!strcmp(token, "selected-fg-color")) {
+ parse_color(&colors->selected_fg);
+ } else if (!strcmp(token, "selected-bg-color")) {
+ parse_color(&colors->selected_bg);
+ } else if (!strcmp(token, "interactive-fg-color")) {
+ parse_color(&colors->interactive_fg);
+ } else if (!strcmp(token, "interactive-bg-color")) {
+ parse_color(&colors->interactive_bg);
+ } else if (!strcmp(token, "mru-entry")) {
+ parse_mru_entry();
+ } else {
+ /* Unrecognized, just ignore rest of line */
+ }
+}
+
+gboolean
+preferences_load(PreferencesData_t *data)
+{
+ FILE *in;
+ char buf[256];
+ gchar *filename;
+
+ filename = gimp_personal_rc_file ("imagemaprc");
+
+ in = g_fopen(filename, "rb");
+ g_free(filename);
+ if (in) {
+ while (fgets(buf, sizeof(buf), in)) {
+ if (*buf != '\n' && *buf != '#') {
+ parse_line(data, buf);
+ }
+ }
+ fclose(in);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+preferences_save(PreferencesData_t *data)
+{
+ FILE *out;
+ gchar *filename;
+ ColorSelData_t *colors = &data->colors;
+
+ filename = gimp_personal_rc_file ("imagemaprc");
+
+ out = g_fopen(filename, "wb");
+ if (out) {
+ fprintf(out, "# Image map plug-in resource file\n\n");
+ if (data->default_map_type == NCSA)
+ fprintf(out, "(default-map-type ncsa)\n");
+ else if (data->default_map_type == CERN)
+ fprintf(out, "(default-map-type cern)\n");
+ else
+ fprintf(out, "(default-map-type csim)\n");
+
+ fprintf(out, "(prompt-for-area-info %s)\n",
+ (data->prompt_for_area_info) ? "yes" : "no");
+ fprintf(out, "(require-default-url %s)\n",
+ (data->require_default_url) ? "yes" : "no");
+ fprintf(out, "(show-area-handle %s)\n",
+ (data->show_area_handle) ? "yes" : "no");
+ fprintf(out, "(keep-circles-round %s)\n",
+ (data->keep_circles_round) ? "yes" : "no");
+ fprintf(out, "(show-url-tip %s)\n",
+ (data->show_url_tip) ? "yes" : "no");
+ fprintf(out, "(use-doublesized %s)\n",
+ (data->use_doublesized) ? "yes" : "no");
+
+ fprintf(out, "(undo-levels %d)\n", data->undo_levels);
+ fprintf(out, "(mru-size %d)\n", data->mru_size);
+
+ fprintf(out, "(normal-fg-color %d %d %d)\n",
+ colors->normal_fg.red, colors->normal_fg.green,
+ colors->normal_fg.blue);
+ fprintf(out, "(normal-bg-color %d %d %d)\n",
+ colors->normal_bg.red, colors->normal_bg.green,
+ colors->normal_bg.blue);
+ fprintf(out, "(selected-fg-color %d %d %d)\n",
+ colors->selected_fg.red, colors->selected_fg.green,
+ colors->selected_fg.blue);
+ fprintf(out, "(selected-bg-color %d %d %d)\n",
+ colors->selected_bg.red, colors->selected_bg.green,
+ colors->selected_bg.blue);
+ fprintf(out, "(interactive-fg-color %d %d %d)\n",
+ colors->interactive_fg.red, colors->interactive_fg.green,
+ colors->interactive_fg.blue);
+ fprintf(out, "(interactive-bg-color %d %d %d)\n",
+ colors->interactive_bg.red, colors->interactive_bg.green,
+ colors->interactive_bg.blue);
+
+ mru_write(get_mru(), out);
+
+ fclose(out);
+ } else {
+ do_file_error_dialog( _("Couldn't save resource file:"), filename);
+ }
+ g_free(filename);
+}
+
+static void
+preferences_ok_cb(gpointer data)
+{
+ PreferencesDialog_t *param = (PreferencesDialog_t*) data;
+ PreferencesData_t *old_data = param->old_data;
+ ColorSelData_t *colors = &old_data->colors;
+ MRU_t *mru = get_mru();
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->cern)))
+ old_data->default_map_type = CERN;
+ else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(param->ncsa)))
+ old_data->default_map_type = NCSA;
+ else
+ old_data->default_map_type = CSIM;
+
+ old_data->prompt_for_area_info = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->prompt_for_area_info));
+ old_data->require_default_url = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->require_default_url));
+ old_data->show_area_handle = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->show_area_handle));
+ old_data->keep_circles_round = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->keep_circles_round));
+ old_data->show_url_tip = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->show_url_tip));
+ old_data->use_doublesized = gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(param->use_doublesized));
+
+ old_data->mru_size =
+ gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->mru_size));
+ old_data->undo_levels =
+ gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(param->undo_levels));
+ mru_set_size(mru, old_data->mru_size);
+ menu_build_mru_items(mru);
+ command_list_set_undo_level(old_data->undo_levels);
+
+ get_button_colors (param, colors);
+
+ set_sash_size(old_data->use_doublesized);
+ preview_redraw();
+}
+
+static void
+get_button_color (GtkWidget *button, GdkColor *color)
+{
+ GimpRGB rgb;
+ gimp_color_button_get_color (GIMP_COLOR_BUTTON (button), &rgb);
+ color->red = rgb.r * 0xffff;
+ color->green = rgb.g * 0xffff;
+ color->blue = rgb.b * 0xffff;
+}
+
+static void
+get_button_colors(PreferencesDialog_t *dialog, ColorSelData_t *colors)
+{
+ get_button_color (dialog->normal_fg, &colors->normal_fg);
+ get_button_color (dialog->normal_bg, &colors->normal_bg);
+ get_button_color (dialog->selected_fg, &colors->selected_fg);
+ get_button_color (dialog->selected_bg, &colors->selected_bg);
+ get_button_color (dialog->interactive_fg, &colors->interactive_fg);
+ get_button_color (dialog->interactive_bg, &colors->interactive_bg);
+}
+
+static void
+set_button_color (GtkWidget *button, GdkColor *color)
+{
+ GimpRGB rgb;
+ gimp_rgb_set (&rgb, color->red, color->green, color->blue);
+ gimp_rgb_multiply (&rgb, 1.0 / 0xffff);
+ gimp_color_button_set_color (GIMP_COLOR_BUTTON (button), &rgb);
+}
+
+static void
+set_button_colors(PreferencesDialog_t *dialog, ColorSelData_t *colors)
+{
+ set_button_color (dialog->normal_fg, &colors->normal_fg);
+ set_button_color (dialog->normal_bg, &colors->normal_bg);
+ set_button_color (dialog->selected_fg, &colors->selected_fg);
+ set_button_color (dialog->selected_bg, &colors->selected_bg);
+ set_button_color (dialog->interactive_fg, &colors->interactive_fg);
+ set_button_color (dialog->interactive_bg, &colors->interactive_bg);
+}
+
+static GtkWidget*
+create_tab(GtkWidget *notebook, const gchar *label, gint rows, gint cols)
+{
+ GtkWidget *table;
+ GtkWidget *vbox;
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
+ gtk_widget_show(vbox);
+
+ table = gtk_table_new(rows, cols, FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 12);
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_widget_show(table);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox,
+ gtk_label_new_with_mnemonic(label));
+
+ return table;
+}
+
+static void
+create_general_tab(PreferencesDialog_t *data, GtkWidget *notebook)
+{
+ GtkWidget *table = create_tab(notebook, _("General"), 7, 2);
+ GtkWidget *frame;
+ GtkWidget *hbox;
+
+ frame = gimp_frame_new( _("Default Map Type"));
+ gtk_widget_show(frame);
+ gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 0, 1);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+ data->ncsa = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_NCSA");
+ gtk_box_pack_start(GTK_BOX(hbox), data->ncsa, TRUE, TRUE, 10);
+ gtk_widget_show(data->ncsa);
+ data->cern = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(data->ncsa), "C_ERN");
+ gtk_box_pack_start(GTK_BOX(hbox), data->cern, TRUE, TRUE, 10);
+ gtk_widget_show(data->cern);
+ data->csim = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(data->cern), "C_SIM");
+ gtk_box_pack_start(GTK_BOX(hbox), data->csim, TRUE, TRUE, 10);
+ gtk_widget_show(data->csim);
+
+ data->prompt_for_area_info =
+ create_check_button_in_table(table, 1, 0, _("_Prompt for area info"));
+ data->require_default_url =
+ create_check_button_in_table(table, 2, 0, _("_Require default URL"));
+ data->show_area_handle =
+ create_check_button_in_table(table, 3, 0, _("Show area _handles"));
+ data->keep_circles_round =
+ create_check_button_in_table(table, 4, 0, _("_Keep NCSA circles true"));
+ data->show_url_tip =
+ create_check_button_in_table(table, 5, 0, _("Show area URL _tip"));
+ data->use_doublesized =
+ create_check_button_in_table(table, 6, 0,
+ _("_Use double-sized grab handles"));
+ gtk_widget_show(frame);
+}
+
+static void
+create_menu_tab(PreferencesDialog_t *data, GtkWidget *notebook)
+{
+ GtkWidget *table = create_tab(notebook, _("Menu"), 2, 2);
+ GtkWidget *label;
+
+ label = create_label_in_table(table, 0, 0,
+ _("Number of _undo levels (1 - 99):"));
+ data->undo_levels = create_spin_button_in_table(table, label, 0, 1, 1, 1,
+ 99);
+
+ label = create_label_in_table(table, 1, 0,
+ _("Number of M_RU entries (1 - 16):"));
+ data->mru_size = create_spin_button_in_table(table, label, 1, 1, 1, 1, 16);
+}
+
+static GtkWidget*
+create_color_field(PreferencesDialog_t *data, GtkWidget *table, gint row,
+ gint col)
+{
+ GimpRGB color = {0.0, 0.0, 0.0, 1.0};
+ GtkWidget *area = gimp_color_button_new (_("Select Color"), 16, 8, &color,
+ GIMP_COLOR_AREA_FLAT);
+ gimp_color_button_set_update (GIMP_COLOR_BUTTON (area), TRUE);
+ gtk_table_attach_defaults (GTK_TABLE (table), area, col, col + 1, row,
+ row + 1);
+ gtk_widget_show (area);
+
+ return area;
+}
+
+static void
+create_colors_tab(PreferencesDialog_t *data, GtkWidget *notebook)
+{
+ GtkWidget *table = create_tab(notebook, _("Colors"), 3, 3);
+
+ create_label_in_table(table, 0, 0, _("Normal:"));
+ data->normal_fg = create_color_field(data, table, 0, 1);
+ data->normal_bg = create_color_field(data, table, 0, 2);
+
+ create_label_in_table(table, 1, 0, _("Selected:"));
+ data->selected_fg = create_color_field(data, table, 1, 1);
+ data->selected_bg = create_color_field(data, table, 1, 2);
+
+ create_label_in_table(table, 2, 0, _("Interaction:"));
+ data->interactive_fg = create_color_field(data, table, 2, 1);
+ data->interactive_bg = create_color_field(data, table, 2, 2);
+}
+
+#ifdef _NOT_READY_YET_
+static void
+create_contiguous_regions_tab(PreferencesDialog_t *data, GtkWidget *notebook)
+{
+ GtkWidget *table = create_tab(notebook, _("Co_ntiguous Region"), 2, 2);
+ GtkWidget *label;
+
+ label = create_label_in_table(table, 0, 0,
+ _("_Threshold:"));
+ data->auto_convert =
+ create_check_button_in_table(table, 1, 0, _("_Automatically convert"));
+}
+#endif
+
+static PreferencesDialog_t*
+create_preferences_dialog(void)
+{
+ PreferencesDialog_t *data = g_new(PreferencesDialog_t, 1);
+ DefaultDialog_t *dialog;
+ GtkWidget *notebook;
+
+ data->dialog = dialog = make_default_dialog( _("General Preferences"));
+ default_dialog_set_ok_cb(dialog, preferences_ok_cb, (gpointer) data);
+
+ data->notebook = notebook = gtk_notebook_new();
+ gtk_box_pack_start (GTK_BOX (data->dialog->vbox), notebook, TRUE, TRUE, 0);
+ create_general_tab(data, notebook);
+ create_menu_tab(data, notebook);
+ create_colors_tab(data, notebook);
+#ifdef _NOT_READY_YET_
+ create_contiguous_regions_tab(data, notebook);
+#endif
+ gtk_widget_show(notebook);
+
+ return data;
+}
+
+void
+do_preferences_dialog(void)
+{
+ static PreferencesDialog_t *dialog;
+ PreferencesData_t *old_data;
+ GtkWidget *map_type;
+
+ if (!dialog) {
+ dialog = create_preferences_dialog();
+ }
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(dialog->notebook), 0);
+ dialog->old_data = old_data = get_preferences();
+
+ if (old_data->default_map_type == CERN)
+ map_type = dialog->cern;
+ else if (old_data->default_map_type == NCSA)
+ map_type = dialog->ncsa;
+ else
+ map_type = dialog->csim;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(map_type), TRUE);
+
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(dialog->prompt_for_area_info),
+ old_data->prompt_for_area_info);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->require_default_url),
+ old_data->require_default_url);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->show_area_handle),
+ old_data->show_area_handle);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->keep_circles_round),
+ old_data->keep_circles_round);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->show_url_tip),
+ old_data->show_url_tip);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->use_doublesized),
+ old_data->use_doublesized);
+
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->undo_levels),
+ old_data->undo_levels);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(dialog->mru_size),
+ old_data->mru_size);
+
+ set_button_colors(dialog, &old_data->colors);
+
+ default_dialog_show(dialog->dialog);
+}
diff --git a/plug-ins/imagemap/imap_preferences.h b/plug-ins/imagemap/imap_preferences.h
new file mode 100644
index 0000000..7376026
--- /dev/null
+++ b/plug-ins/imagemap/imap_preferences.h
@@ -0,0 +1,56 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_PREFERENCES_H
+#define _IMAP_PREFERENCES_H
+
+#include "imap_default_dialog.h"
+
+typedef struct {
+ GdkColor normal_fg;
+ GdkColor normal_bg;
+ GdkColor selected_fg;
+ GdkColor selected_bg;
+ GdkColor interactive_bg;
+ GdkColor interactive_fg;
+} ColorSelData_t;
+
+typedef struct {
+ gint default_map_type;
+ gboolean prompt_for_area_info;
+ gboolean require_default_url;
+ gboolean show_area_handle;
+ gboolean keep_circles_round;
+ gboolean show_url_tip;
+ gboolean use_doublesized;
+ gboolean auto_convert;
+ gdouble threshold;
+ gint undo_levels;
+ gint mru_size;
+ ColorSelData_t colors;
+} PreferencesData_t;
+
+void do_preferences_dialog(void);
+gboolean preferences_load(PreferencesData_t *data);
+void preferences_save(PreferencesData_t *data);
+
+#endif /* _IMAP_PREFERENCES_H */
diff --git a/plug-ins/imagemap/imap_preview.c b/plug-ins/imagemap/imap_preview.c
new file mode 100644
index 0000000..160a88d
--- /dev/null
+++ b/plug-ins/imagemap/imap_preview.c
@@ -0,0 +1,402 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <libgimp/gimpui.h>
+
+#include "imap_commands.h"
+#include "imap_grid.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_preview.h"
+
+#define PREVIEW_MASK (GDK_EXPOSURE_MASK | \
+ GDK_POINTER_MOTION_MASK | \
+ GDK_BUTTON_PRESS_MASK | \
+ GDK_BUTTON_RELEASE_MASK | \
+ GDK_BUTTON_MOTION_MASK | \
+ GDK_KEY_PRESS_MASK | \
+ GDK_KEY_RELEASE_MASK | \
+ GDK_ENTER_NOTIFY_MASK | \
+ GDK_LEAVE_NOTIFY_MASK)
+
+#define PREVIEW_SIZE 400
+
+/*======================================================================
+ Preview Rendering Util routine
+=======================================================================*/
+
+#define CHECKWIDTH 4
+#define LIGHTCHECK 192
+#define DARKCHECK 128
+#ifndef OPAQUE
+#define OPAQUE 255
+#endif
+
+static Object_t *_tmp_obj;
+
+static Preview_t*
+preview_user_data(GtkWidget *preview)
+{
+ return (Preview_t*) g_object_get_data (G_OBJECT (preview), "preview");
+}
+
+gint
+preview_get_width(GtkWidget *preview)
+{
+ return preview_user_data(preview)->width;
+}
+
+gint
+preview_get_height(GtkWidget *preview)
+{
+ return preview_user_data(preview)->height;
+}
+
+static void
+render_background(Preview_t *preview_base)
+{
+ GtkWidget *preview = preview_base->preview;
+ GtkStyle *style;
+ const GdkColor *bg_color;
+
+ gtk_widget_ensure_style (preview);
+
+ style = gtk_widget_get_style (preview);
+ bg_color = &style->bg[GTK_STATE_NORMAL];
+
+ gimp_preview_area_fill (GIMP_PREVIEW_AREA (preview),
+ 0, 0, G_MAXINT, G_MAXINT,
+ bg_color->red >> 8,
+ bg_color->green >> 8,
+ bg_color->blue >> 8);
+}
+
+static void
+render_rgb_image (Preview_t *preview_base,
+ gint32 drawable_id)
+{
+ GeglBuffer *buffer;
+ guchar *dest_buffer;
+ gint dwidth, dheight, pwidth, pheight;
+ GtkWidget *preview = preview_base->preview;
+
+ dwidth = gimp_drawable_width (drawable_id);
+ dheight = gimp_drawable_height (drawable_id);
+ pwidth = preview_base->widget_width;
+ pheight = preview_base->widget_height;
+
+ dest_buffer = g_new (guchar, pwidth * pheight * 4);
+
+ buffer = gimp_drawable_get_buffer (drawable_id);
+
+ gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, pwidth, pheight),
+ MIN ((gdouble) pwidth / (gdouble) dwidth,
+ (gdouble) pheight / (gdouble) dheight),
+ babl_format ("R'G'B'A u8"), dest_buffer,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ g_object_unref (buffer);
+
+ gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
+ 0, 0, pwidth, pheight,
+ GIMP_RGBA_IMAGE,
+ dest_buffer,
+ pwidth * 4);
+
+ g_free (dest_buffer);
+}
+
+static void
+render_preview (Preview_t *preview_base,
+ gint32 drawable_id)
+{
+ render_background (preview_base);
+ render_rgb_image (preview_base, drawable_id);
+}
+
+static gboolean
+arrow_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ if (event->button == 1)
+ do_main_popup_menu(event);
+ return TRUE;
+}
+
+static gboolean
+preview_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+ cairo_t *cr;
+ gint width = preview_get_width (widget);
+ gint height = preview_get_height (widget);
+
+ cr = gdk_cairo_create (event->window);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+ cairo_set_line_width (cr, 1.);
+ draw_grid (cr, width, height);
+
+ draw_shapes (cr);
+
+ if (_tmp_obj)
+ {
+ /* this is a bit of a hack */
+ gdouble dash = 4.;
+ _tmp_obj->selected |= 4;
+ cairo_set_source_rgb (cr, 1., 0., 1.);
+ cairo_set_dash (cr, &dash, 1, dash);
+ object_draw (_tmp_obj, cr);
+ }
+
+ cairo_destroy (cr);
+ return FALSE;
+}
+
+void
+preview_set_tmp_obj (Object_t *obj)
+{
+ _tmp_obj = obj;
+}
+
+void
+preview_unset_tmp_obj (Object_t *obj)
+{
+ if (_tmp_obj == obj) _tmp_obj = NULL;
+}
+
+void
+preview_zoom(Preview_t *preview, gint zoom_factor)
+{
+ preview->widget_width = preview->width * zoom_factor;
+ preview->widget_height = preview->height * zoom_factor;
+ gtk_widget_set_size_request (preview->preview, preview->widget_width,
+ preview->widget_height);
+ gtk_widget_queue_resize(preview->window);
+ render_preview(preview, preview->drawable_id);
+ preview_redraw();
+}
+
+GdkCursorType
+preview_set_cursor(Preview_t *preview, GdkCursorType cursor_type)
+{
+ GdkCursorType prev_cursor = preview->cursor;
+ GdkDisplay *display = gtk_widget_get_display (preview->window);
+ GdkCursor *cursor = gdk_cursor_new_for_display (display,
+ cursor_type);
+
+ gdk_window_set_cursor(gtk_widget_get_window (preview->window), cursor);
+ gdk_cursor_unref(cursor);
+
+ preview->cursor = cursor_type;
+
+ return prev_cursor;
+}
+
+static const GtkTargetEntry target_table[] =
+{
+ {"STRING", 0, 1 },
+ {"text/plain", 0, 2 }
+};
+
+static void
+handle_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *data, guint info, guint time)
+{
+ gboolean success = FALSE;
+
+ if (gtk_selection_data_get_length (data) >= 0 &&
+ gtk_selection_data_get_format (data) == 8)
+ {
+ ObjectList_t *list = get_shapes();
+ Object_t *obj;
+
+ x = get_real_coord(x);
+ y = get_real_coord(y);
+ obj = object_list_find(list, x, y);
+ if (obj && !obj->locked)
+ {
+ command_list_add(edit_object_command_new(obj));
+ object_set_url(obj, (const gchar *) gtk_selection_data_get_data (data));
+ object_emit_update_signal(obj);
+ success = TRUE;
+ }
+ }
+ gtk_drag_finish(context, success, FALSE, time);
+}
+
+static void
+preview_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation,
+ gpointer preview_void)
+{
+ Preview_t *preview = preview_void;
+
+ render_preview (preview, preview->drawable_id);
+}
+
+static void
+scroll_adj_changed (GtkAdjustment *adj,
+ GimpRuler *ruler)
+{
+ gimp_ruler_set_range (ruler,
+ gtk_adjustment_get_value (adj),
+ gtk_adjustment_get_value (adj) +
+ gtk_adjustment_get_page_size (adj),
+ gtk_adjustment_get_upper (adj));
+}
+
+Preview_t *
+make_preview (gint32 drawable_id)
+{
+ Preview_t *data = g_new(Preview_t, 1);
+ GtkAdjustment *hadj;
+ GtkAdjustment *vadj;
+ GtkWidget *preview;
+ GtkWidget *window;
+ GtkWidget *viewport;
+ GtkWidget *button, *arrow;
+ GtkWidget *ruler;
+ GtkWidget *table;
+ GtkWidget *scrollbar;
+ gint width, height;
+
+ data->drawable_id = drawable_id;
+ data->preview = preview = gimp_preview_area_new ();
+
+ g_object_set_data (G_OBJECT (preview), "preview", data);
+ gtk_widget_set_events (GTK_WIDGET (preview), PREVIEW_MASK);
+
+ g_signal_connect_after (preview, "expose-event",
+ G_CALLBACK (preview_expose),
+ data);
+ g_signal_connect (preview, "size-allocate",
+ G_CALLBACK (preview_size_allocate),
+ data);
+
+ /* Handle drop of links in preview widget */
+ gtk_drag_dest_set (preview, GTK_DEST_DEFAULT_ALL, target_table,
+ 2, GDK_ACTION_COPY);
+
+ g_signal_connect (preview, "drag-data-received",
+ G_CALLBACK (handle_drop),
+ NULL);
+
+ data->widget_width = data->width = gimp_drawable_width (drawable_id);
+ data->widget_height = data->height = gimp_drawable_height (drawable_id);
+ gtk_widget_set_size_request (preview, data->widget_width,
+ data->widget_height);
+
+ /* The main table */
+ data->window = table = gtk_table_new (3, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 1);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 1);
+
+ /* Create button with arrow */
+ button = gtk_button_new ();
+ gtk_widget_set_can_focus (button, FALSE);
+ gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_set_events (button,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "button-press-event",
+ G_CALLBACK (arrow_cb),
+ NULL);
+
+ arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
+ gtk_container_add (GTK_CONTAINER (button), arrow);
+ gtk_widget_show (arrow);
+
+ /* Create horizontal ruler */
+ data->hruler = ruler = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
+ g_signal_connect_swapped (preview, "motion-notify-event",
+ G_CALLBACK (GTK_WIDGET_GET_CLASS (ruler)->motion_notify_event),
+ ruler);
+
+ gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show (ruler);
+
+ /* Create vertical ruler */
+ data->vruler = ruler = gimp_ruler_new (GTK_ORIENTATION_VERTICAL);
+ g_signal_connect_swapped (preview, "motion-notify-event",
+ G_CALLBACK (GTK_WIDGET_GET_CLASS (ruler)->motion_notify_event),
+ ruler);
+ gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2,
+ GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (ruler);
+
+ window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window),
+ GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+ width = (data->width > 600) ? 600 : data->width;
+ height = (data->height > 400) ? 400 : data->height;
+ gtk_widget_set_size_request (window, width, height);
+ gtk_table_attach (GTK_TABLE (table), window, 1, 2, 1, 2,
+ GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show (window);
+
+ viewport = gtk_viewport_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (window), viewport);
+ gtk_widget_show (viewport);
+
+ hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (window));
+
+ g_signal_connect (hadj, "changed",
+ G_CALLBACK (scroll_adj_changed),
+ data->hruler);
+ g_signal_connect (hadj, "value-changed",
+ G_CALLBACK (scroll_adj_changed),
+ data->hruler);
+
+ vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (window));
+
+ g_signal_connect (vadj, "changed",
+ G_CALLBACK (scroll_adj_changed),
+ data->vruler);
+ g_signal_connect (vadj, "value-changed",
+ G_CALLBACK (scroll_adj_changed),
+ data->vruler);
+
+ gtk_container_add (GTK_CONTAINER (viewport), preview);
+
+ scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, hadj);
+ gtk_table_attach(GTK_TABLE(table), scrollbar, 1, 2, 2, 3,
+ GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
+ gtk_widget_show (scrollbar);
+
+ scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, vadj);
+ gtk_table_attach (GTK_TABLE (table), scrollbar, 2, 3, 1, 2,
+ GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
+ gtk_widget_show (scrollbar);
+
+ gtk_widget_show (preview);
+
+ render_preview (data, drawable_id);
+
+ gtk_widget_show (table);
+
+ return data;
+}
diff --git a/plug-ins/imagemap/imap_preview.h b/plug-ins/imagemap/imap_preview.h
new file mode 100644
index 0000000..3fe01c4
--- /dev/null
+++ b/plug-ins/imagemap/imap_preview.h
@@ -0,0 +1,55 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_PREVIEW_H
+#define _IMAP_PREVIEW_H
+
+#include <libgimp/gimp.h>
+
+typedef struct {
+ gint32 drawable_id;
+ GtkWidget *window;
+ GtkWidget *preview;
+ GtkWidget *hruler;
+ GtkWidget *vruler;
+ gint width;
+ gint height;
+ gint widget_width;
+ gint widget_height;
+
+ GdkCursorType cursor;
+} Preview_t;
+
+Preview_t *make_preview(gint32 drawable_id);
+void preview_redraw(void);
+
+void preview_unset_tmp_obj (Object_t *obj);
+void preview_set_tmp_obj (Object_t *obj);
+
+gint preview_get_width(GtkWidget *preview);
+gint preview_get_height(GtkWidget *preview);
+
+void preview_zoom(Preview_t *preview, gint zoom_factor);
+GdkCursorType preview_set_cursor(Preview_t *preview,
+ GdkCursorType cursor_type);
+
+#endif /* _IMAP_PREVIEW_H */
diff --git a/plug-ins/imagemap/imap_rectangle.c b/plug-ins/imagemap/imap_rectangle.c
new file mode 100644
index 0000000..fa4c3a9
--- /dev/null
+++ b/plug-ins/imagemap/imap_rectangle.c
@@ -0,0 +1,538 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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> /* abs */
+
+#include <gtk/gtk.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "imap_main.h"
+#include "imap_misc.h"
+#include "imap_object_popup.h"
+#include "imap_rectangle.h"
+#include "imap_stock.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static gboolean rectangle_is_valid(Object_t *obj);
+static Object_t *rectangle_clone(Object_t *obj);
+static void rectangle_assign(Object_t *obj, Object_t *des);
+static void rectangle_normalize(Object_t *obj);
+static void rectangle_draw(Object_t *obj, cairo_t *cr);
+static void rectangle_draw_sashes(Object_t *obj, cairo_t *cr);
+static MoveSashFunc_t rectangle_near_sash(Object_t *obj, gint x, gint y);
+static gboolean rectangle_point_is_on(Object_t *obj, gint x, gint y);
+static void rectangle_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height);
+static void rectangle_resize(Object_t *obj, gint percentage_x,
+ gint percentage_y);
+static void rectangle_move(Object_t *obj, gint dx, gint dy);
+static gpointer rectangle_create_info_widget(GtkWidget *frame);
+static void rectangle_fill_info_tab(Object_t *obj, gpointer data);
+static void rectangle_set_initial_focus(Object_t *obj, gpointer data);
+static void rectangle_update(Object_t *obj, gpointer data);
+static void rectangle_write_csim(Object_t *obj, gpointer param,
+ OutputFunc_t output);
+static void rectangle_write_cern(Object_t *obj, gpointer param,
+ OutputFunc_t output);
+static void rectangle_write_ncsa(Object_t *obj, gpointer param,
+ OutputFunc_t output);
+static const gchar* rectangle_get_stock_icon_name(void);
+
+static ObjectClass_t rectangle_class = {
+ N_("_Rectangle"),
+ NULL, /* info_dialog */
+
+ rectangle_is_valid,
+ NULL, /* rectangle_destruct */
+ rectangle_clone,
+ rectangle_assign,
+ rectangle_normalize,
+ rectangle_draw,
+ rectangle_draw_sashes,
+ rectangle_near_sash,
+ rectangle_point_is_on,
+ rectangle_get_dimensions,
+ rectangle_resize,
+ rectangle_move,
+ rectangle_create_info_widget,
+ rectangle_fill_info_tab, /* rectangle_update_info_widget */
+ rectangle_fill_info_tab,
+ rectangle_set_initial_focus,
+ rectangle_update,
+ rectangle_write_csim,
+ rectangle_write_cern,
+ rectangle_write_ncsa,
+ object_do_popup,
+ rectangle_get_stock_icon_name
+};
+
+Object_t*
+create_rectangle(gint x, gint y, gint width, gint height)
+{
+ Rectangle_t *rectangle = g_new(Rectangle_t, 1);
+ rectangle->x = x;
+ rectangle->y = y;
+ rectangle->width = width;
+ rectangle->height = height;
+ return object_init(&rectangle->obj, &rectangle_class);
+}
+
+static void
+draw_any_rectangle(cairo_t *cr, gint x, gint y, gint w, gint h)
+{
+ if (w < 0) {
+ x += w;
+ w = -w;
+ }
+ if (h < 0) {
+ y += h;
+ h = -h;
+ }
+ draw_rectangle(cr, FALSE, x, y, w, h);
+}
+
+static gboolean
+rectangle_is_valid(Object_t *obj)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ return rectangle->width && rectangle->height;
+}
+
+static Object_t*
+rectangle_clone(Object_t *obj)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ Rectangle_t *clone = g_new(Rectangle_t, 1);
+
+ clone->x = rectangle->x;
+ clone->y = rectangle->y;
+ clone->width = rectangle->width;
+ clone->height = rectangle->height;
+ return &clone->obj;
+}
+
+static void
+rectangle_assign(Object_t *obj, Object_t *des)
+{
+ Rectangle_t *src_rectangle = ObjectToRectangle(obj);
+ Rectangle_t *des_rectangle = ObjectToRectangle(des);
+ des_rectangle->x = src_rectangle->x;
+ des_rectangle->y = src_rectangle->y;
+ des_rectangle->width = src_rectangle->width;
+ des_rectangle->height = src_rectangle->height;
+}
+
+static void
+rectangle_normalize(Object_t *obj)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ if (rectangle->width < 0) {
+ rectangle->x += rectangle->width;
+ rectangle->width = -rectangle->width;
+ }
+ if (rectangle->height < 0) {
+ rectangle->y += rectangle->height;
+ rectangle->height = -rectangle->height;
+ }
+}
+
+static void
+rectangle_draw(Object_t *obj, cairo_t *cr)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ draw_any_rectangle(cr, rectangle->x, rectangle->y,
+ rectangle->width, rectangle->height);
+}
+
+static void
+rectangle_draw_sashes(Object_t *obj, cairo_t *cr)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ draw_sash(cr, rectangle->x, rectangle->y);
+ draw_sash(cr, rectangle->x + rectangle->width / 2, rectangle->y);
+ draw_sash(cr, rectangle->x + rectangle->width, rectangle->y);
+ draw_sash(cr, rectangle->x, rectangle->y + rectangle->height / 2);
+ draw_sash(cr, rectangle->x + rectangle->width,
+ rectangle->y + rectangle->height / 2);
+ draw_sash(cr, rectangle->x, rectangle->y + rectangle->height);
+ draw_sash(cr, rectangle->x + rectangle->width / 2,
+ rectangle->y + rectangle->height);
+ draw_sash(cr, rectangle->x + rectangle->width,
+ rectangle->y + rectangle->height);
+}
+
+static void
+MoveUpperSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->y += dy;
+ rectangle->height -= dy;
+}
+
+static void
+MoveLeftSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->x += dx;
+ rectangle->width -= dx;
+}
+
+static void
+MoveRightSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->width += dx;
+}
+
+static void
+MoveLowerSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->height += dy;
+}
+
+static void
+MoveUpperLeftSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->x += dx;
+ rectangle->y += dy;
+ rectangle->width -= dx;
+ rectangle->height -= dy;
+}
+
+static void
+MoveUpperRightSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->y += dy;
+ rectangle->width += dx;
+ rectangle->height -= dy;
+}
+
+static void
+MoveLowerLeftSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->x += dx;
+ rectangle->width -= dx;
+ rectangle->height += dy;
+}
+
+static void
+MoveLowerRightSash(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->width += dx;
+ rectangle->height += dy;
+}
+
+static MoveSashFunc_t
+rectangle_near_sash(Object_t *obj, gint x, gint y)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ if (near_sash(rectangle->x, rectangle->y, x, y))
+ return MoveUpperLeftSash;
+ else if (near_sash(rectangle->x + rectangle->width / 2, rectangle->y, x, y))
+ return MoveUpperSash;
+ else if (near_sash(rectangle->x + rectangle->width, rectangle->y, x, y))
+ return MoveUpperRightSash;
+ else if (near_sash(rectangle->x, rectangle->y + rectangle->height / 2,
+ x, y))
+ return MoveLeftSash;
+ else if (near_sash(rectangle->x + rectangle->width,
+ rectangle->y + rectangle->height / 2, x, y))
+ return MoveRightSash;
+ else if (near_sash(rectangle->x, rectangle->y + rectangle->height, x, y))
+ return MoveLowerLeftSash;
+ else if (near_sash(rectangle->x + rectangle->width / 2,
+ rectangle->y + rectangle->height, x, y))
+ return MoveLowerSash;
+ else if (near_sash(rectangle->x + rectangle->width,
+ rectangle->y + rectangle->height, x, y))
+ return MoveLowerRightSash;
+ return NULL;
+}
+
+static gboolean
+rectangle_point_is_on(Object_t *obj, gint x, gint y)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ return x >= rectangle->x && x <= rectangle->x + rectangle->width &&
+ y >= rectangle->y && y <= rectangle->y + rectangle->height;
+}
+
+static void
+rectangle_get_dimensions(Object_t *obj, gint *x, gint *y,
+ gint *width, gint *height)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ *x = rectangle->x;
+ *y = rectangle->y;
+ *width = rectangle->width;
+ *height = rectangle->height;
+}
+
+static void
+rectangle_resize(Object_t *obj, gint percentage_x, gint percentage_y)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->x = rectangle->x * percentage_x / 100;
+ rectangle->y = rectangle->y * percentage_y / 100;
+ rectangle->width = rectangle->width * percentage_x / 100;
+ rectangle->height = rectangle->height * percentage_y / 100;
+}
+
+static void
+rectangle_move(Object_t *obj, gint dx, gint dy)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ rectangle->x += dx;
+ rectangle->y += dy;
+}
+
+typedef struct {
+ Object_t *obj;
+ GtkWidget *x;
+ GtkWidget *y;
+ GtkWidget *width;
+ GtkWidget *height;
+ GtkWidget *chain_button;
+} RectangleProperties_t;
+
+static void
+x_changed_cb(GtkWidget *widget, gpointer data)
+{
+ RectangleProperties_t *props = (RectangleProperties_t*) data;
+ Object_t *obj = props->obj;
+ gint x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+
+ if (gimp_chain_button_get_active(GIMP_CHAIN_BUTTON(props->chain_button)))
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), x);
+
+ ObjectToRectangle(obj)->x = x;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+y_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((RectangleProperties_t*) data)->obj;
+ gint y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToRectangle(obj)->y = y;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+width_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((RectangleProperties_t*) data)->obj;
+ gint width = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToRectangle(obj)->width = width;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static void
+height_changed_cb(GtkWidget *widget, gpointer data)
+{
+ Object_t *obj = ((RectangleProperties_t*) data)->obj;
+ gint height = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+ ObjectToRectangle(obj)->height = height;
+ edit_area_info_dialog_emit_geometry_signal(obj->class->info_dialog);
+}
+
+static gpointer
+rectangle_create_info_widget(GtkWidget *frame)
+{
+ RectangleProperties_t *props = g_new(RectangleProperties_t, 1);
+ GtkWidget *table, *label, *chain_button;
+ gint max_width = get_image_width();
+ gint max_height = get_image_height();
+
+ table = gtk_table_new(4, 4, FALSE);
+ gtk_container_add(GTK_CONTAINER(frame), table);
+
+ gtk_table_set_row_spacings(GTK_TABLE(table), 6);
+ gtk_table_set_col_spacings(GTK_TABLE(table), 6);
+ gtk_widget_show(table);
+
+ label = create_label_in_table(table, 0, 0, _("Upper left _x:"));
+ props->x = create_spin_button_in_table(table, label, 0, 1, 1, 0,
+ max_width - 1);
+ g_signal_connect(props->x, "value-changed",
+ G_CALLBACK(x_changed_cb), (gpointer) props);
+ create_label_in_table(table, 0, 3, _("pixels"));
+
+ label = create_label_in_table(table, 1, 0, _("Upper left _y:"));
+ props->y = create_spin_button_in_table(table, label, 1, 1, 1, 0,
+ max_height - 1);
+ g_signal_connect(props->y, "value-changed",
+ G_CALLBACK(y_changed_cb), (gpointer) props);
+ create_label_in_table(table, 1, 3, _("pixels"));
+
+ label = create_label_in_table(table, 2, 0, _("_Width:"));
+ props->width = create_spin_button_in_table(table, label, 2, 1, 1, 1,
+ max_width);
+ g_signal_connect(props->width, "value-changed",
+ G_CALLBACK(width_changed_cb), (gpointer) props);
+ create_label_in_table(table, 2, 3, _("pixels"));
+
+ label = create_label_in_table(table, 3, 0, _("_Height:"));
+ props->height = create_spin_button_in_table(table, label, 3, 1, 1, 1,
+ max_height);
+ g_signal_connect(props->height, "value-changed",
+ G_CALLBACK(height_changed_cb), (gpointer) props);
+ create_label_in_table(table, 3, 3, _("pixels"));
+
+ chain_button = gimp_chain_button_new(GIMP_CHAIN_RIGHT);
+ props->chain_button = chain_button;
+ gtk_table_attach_defaults(GTK_TABLE(table), chain_button, 2, 3, 2, 4);
+ gtk_widget_show(chain_button);
+
+ return props;
+}
+
+static void
+rectangle_fill_info_tab(Object_t *obj, gpointer data)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ RectangleProperties_t *props = (RectangleProperties_t*) data;
+
+ props->obj = obj;
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->x), rectangle->x);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->y), rectangle->y);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->width), rectangle->width);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(props->height),
+ rectangle->height);
+}
+
+static void
+rectangle_set_initial_focus(Object_t *obj, gpointer data)
+{
+ RectangleProperties_t *props = (RectangleProperties_t*) data;
+ gtk_widget_grab_focus(props->x);
+}
+
+static void
+rectangle_update(Object_t* obj, gpointer data)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ RectangleProperties_t *props = (RectangleProperties_t*) data;
+
+ rectangle->x = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->x));
+ rectangle->y = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(props->y));
+ rectangle->width = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(props->width));
+ rectangle->height = gtk_spin_button_get_value_as_int(
+ GTK_SPIN_BUTTON(props->height));
+}
+
+static void
+rectangle_write_csim(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ output(param, "\"rect\" coords=\"%d,%d,%d,%d\"", rectangle->x, rectangle->y,
+ rectangle->x + rectangle->width, rectangle->y + rectangle->height);
+}
+
+static void
+rectangle_write_cern(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ output(param, "rect (%d,%d) (%d,%d)", rectangle->x, rectangle->y,
+ rectangle->x + rectangle->width, rectangle->y + rectangle->height);
+}
+
+static void
+rectangle_write_ncsa(Object_t *obj, gpointer param, OutputFunc_t output)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+ output(param, "rect %s %d,%d %d,%d", obj->url,
+ rectangle->x, rectangle->y,
+ rectangle->x + rectangle->width, rectangle->y + rectangle->height);
+}
+
+static const gchar*
+rectangle_get_stock_icon_name(void)
+{
+ return IMAP_STOCK_RECTANGLE;
+}
+
+static gboolean
+rectangle_factory_finish(Object_t *obj, gint x, gint y)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+
+ rectangle->width = x - rectangle->x;
+ rectangle->height = y - rectangle->y;
+
+ rectangle_normalize(obj);
+
+ return TRUE;
+}
+
+static Object_t*
+rectangle_factory_create_object(gint x, gint y)
+{
+ return create_rectangle(x, y, 0, 0);
+}
+
+static void
+rectangle_factory_set_xy(Object_t *obj, guint state, gint x, gint y)
+{
+ Rectangle_t *rectangle = ObjectToRectangle(obj);
+
+ rectangle->width = x - rectangle->x;
+ rectangle->height = y - rectangle->y;
+
+ if (state & GDK_SHIFT_MASK){
+ gint width = abs(rectangle->width);
+ gint height = abs(rectangle->height);
+ if (width < height)
+ rectangle->height = (rectangle->height < 0) ? -width : width;
+ else
+ rectangle->width = (rectangle->width < 0) ? -height : height;
+ }
+
+ main_set_dimension(rectangle->width, rectangle->height);
+}
+
+static ObjectFactory_t rectangle_factory = {
+ NULL, /* Object pointer */
+ rectangle_factory_finish,
+ NULL, /* Cancel func */
+ rectangle_factory_create_object,
+ rectangle_factory_set_xy
+};
+
+ObjectFactory_t*
+get_rectangle_factory(guint state)
+{
+ return &rectangle_factory;
+}
diff --git a/plug-ins/imagemap/imap_rectangle.h b/plug-ins/imagemap/imap_rectangle.h
new file mode 100644
index 0000000..fe33e31
--- /dev/null
+++ b/plug-ins/imagemap/imap_rectangle.h
@@ -0,0 +1,41 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_RECTANGLE_H
+#define _IMAP_RECTANGLE_H
+
+#include "imap_object.h"
+
+typedef struct {
+ Object_t obj;
+ gint x;
+ gint y;
+ gint width;
+ gint height;
+} Rectangle_t;
+
+#define ObjectToRectangle(obj) ((Rectangle_t*) (obj))
+
+Object_t* create_rectangle(gint x, gint y, gint width, gint height);
+ObjectFactory_t *get_rectangle_factory(guint state);
+
+#endif /* _IMAP_RECTANGLE_H */
diff --git a/plug-ins/imagemap/imap_selection.c b/plug-ins/imagemap/imap_selection.c
new file mode 100644
index 0000000..4713d17
--- /dev/null
+++ b/plug-ins/imagemap/imap_selection.c
@@ -0,0 +1,452 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "imap_commands.h"
+#include "imap_main.h"
+#include "imap_menu.h"
+#include "imap_selection.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static void
+changed_cb(GtkTreeSelection *selection, gpointer param)
+{
+ Selection_t *data = (Selection_t*) param;
+
+ if (data->select_lock)
+ {
+ data->select_lock = FALSE;
+ } else
+ {
+ Command_t *command, *sub_command;
+ GtkTreeModel *model;
+ GList *list, *selected_rows;
+
+ selected_rows = gtk_tree_selection_get_selected_rows (selection,
+ &model);
+
+ command = subcommand_start (NULL);
+ sub_command = unselect_all_command_new (data->object_list, NULL);
+ command_add_subcommand (command, sub_command);
+
+ for (list = selected_rows; list; list = list->next)
+ {
+ Object_t *obj;
+ GtkTreeIter iter;
+ GtkTreePath *path = (GtkTreePath*) list->data;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, 0, &obj, -1);
+
+ sub_command = select_command_new (obj);
+ command_add_subcommand (command, sub_command);
+ }
+
+ command_set_name (command, sub_command->name);
+ subcommand_end ();
+
+ command_execute (command);
+
+ g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
+ }
+}
+
+static gboolean
+button_press_cb(GtkWidget *widget, GdkEventButton *event, Selection_t *data)
+{
+ if (event->button == 1) {
+ if (data->doubleclick) {
+ GtkTreePath *path;
+
+ data->doubleclick = FALSE;
+
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
+ (gint) event->x, (gint) event->y,
+ &path, NULL, NULL, NULL)) {
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (data->store), &iter,
+ path)) {
+ Object_t *obj;
+ gtk_tree_model_get (GTK_TREE_MODEL(data->store), &iter, 0, &obj, -1);
+ object_edit (obj, TRUE);
+ }
+ gtk_tree_path_free (path);
+ }
+ } else {
+ data->doubleclick = TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gboolean
+button_release_cb(GtkWidget *widget, GdkEventButton *event, Selection_t *data)
+{
+ if (event->button == 1)
+ data->doubleclick = FALSE;
+ return FALSE;
+}
+
+static void
+selection_set_selected(Selection_t *selection, gint row)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (selection->store), &iter,
+ NULL, row)) {
+ Object_t *obj;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(selection->store), &iter, 0, &obj, -1);
+
+ selection->select_lock = TRUE;
+
+ if (obj->selected) {
+ gtk_tree_selection_select_iter (selection->selection, &iter);
+ } else {
+ gtk_tree_selection_unselect_iter (selection->selection, &iter);
+ }
+ }
+}
+
+static void
+object_added_cb(Object_t *obj, gpointer data)
+{
+ Selection_t *selection = (Selection_t*) data;
+ GtkTreeIter iter;
+ gint position = object_get_position_in_list (obj);
+
+ selection->nr_rows++;
+ if (position < selection->nr_rows - 1) {
+ gtk_list_store_insert (selection->store, &iter, position);
+ } else {
+ gtk_list_store_append (selection->store, &iter);
+ }
+ gtk_list_store_set (selection->store, &iter, 0, obj, -1);
+}
+
+static gboolean
+selection_find_object(Selection_t *selection, Object_t *lookup,
+ GtkTreeIter *iter)
+{
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (selection->store),
+ iter)) {
+ do {
+ Object_t *obj;
+
+ gtk_tree_model_get (GTK_TREE_MODEL(selection->store), iter, 0,
+ &obj, -1);
+ if (obj == lookup)
+ return TRUE;
+
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (selection->store),
+ iter));
+ }
+ return FALSE;
+}
+
+static void
+object_updated_cb(Object_t *obj, gpointer data)
+{
+ Selection_t *selection = (Selection_t*) data;
+ GtkTreeIter iter;
+
+ if (selection_find_object (selection, obj, &iter)) {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (selection->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (selection->store), path,
+ &iter);
+ }
+}
+
+static void
+object_removed_cb(Object_t *obj, gpointer data)
+{
+ Selection_t *selection = (Selection_t*) data;
+ GtkTreeIter iter;
+
+ if (selection_find_object (selection, obj, &iter)) {
+ gtk_list_store_remove (GTK_LIST_STORE (selection->store), &iter);
+ }
+}
+
+static void
+object_selected_cb(Object_t *obj, gpointer data)
+{
+ Selection_t *selection = (Selection_t*) data;
+ gint position = object_get_position_in_list (obj);
+ selection_set_selected (selection, position);
+}
+
+static void
+object_moved_cb(Object_t *obj, gpointer data)
+{
+ Selection_t *selection = (Selection_t*) data;
+ selection->select_lock = TRUE;
+}
+
+static const GtkTargetEntry target_table[] =
+{
+ {"STRING", 0, 1 },
+ {"text/plain", 0, 2 }
+};
+
+static Object_t*
+selection_get_object (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+ Object_t *obj;
+ gtk_tree_model_get (tree_model, iter, 0, &obj, -1);
+ return obj;
+}
+
+static void
+handle_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
+ GtkSelectionData *data, guint info, guint time)
+{
+ gboolean success = FALSE;
+
+ if (gtk_selection_data_get_length (data) >= 0 &&
+ gtk_selection_data_get_format (data) == 8)
+ {
+ GtkTreePath *path;
+
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y,
+ &path, NULL, NULL, NULL))
+ {
+ GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ {
+ Object_t *obj = selection_get_object (model, &iter);
+
+ if (!obj->locked)
+ {
+ command_list_add(edit_object_command_new (obj));
+ object_set_url (obj, (const gchar *) gtk_selection_data_get_data (data));
+ object_emit_update_signal (obj);
+ success = TRUE;
+ }
+ }
+ gtk_tree_path_free (path);
+ }
+ }
+ gtk_drag_finish(context, success, FALSE, time);
+}
+
+static void
+render_image (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ Object_t *obj = selection_get_object (tree_model, iter);
+ g_object_set(cell, "stock-id", object_get_stock_icon_name(obj), NULL);
+}
+
+static void
+render_nr (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ Object_t *obj = selection_get_object (tree_model, iter);
+ gchar *scratch;
+
+ scratch = g_strdup_printf ("%d", object_get_position_in_list (obj) + 1);
+ g_object_set (cell, "text", scratch, NULL);
+ g_free (scratch);
+}
+
+static void
+render_url (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ Object_t *obj = selection_get_object (tree_model, iter);
+ g_object_set (cell, "text", obj->url, NULL);
+}
+
+static void
+render_target (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ Object_t *obj = selection_get_object (tree_model, iter);
+ g_object_set (cell, "text", obj->target, NULL);
+}
+
+static void
+render_comment (GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
+{
+ Object_t *obj = selection_get_object (tree_model, iter);
+ g_object_set (cell, "text", obj->comment, NULL);
+}
+
+Selection_t*
+make_selection(ObjectList_t *object_list)
+{
+ Selection_t *data = g_new(Selection_t, 1);
+ GtkWidget *swin, *frame, *hbox;
+ GtkWidget *toolbar;
+ GtkWidget *list;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ data->object_list = object_list;
+ data->selected_child = NULL;
+ data->is_visible = TRUE;
+ data->nr_rows = 0;
+ data->select_lock = FALSE;
+ data->doubleclick = FALSE;
+
+ data->container = frame = gtk_frame_new(NULL);
+ gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
+ gtk_widget_show(frame);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+
+ toolbar = make_selection_toolbar ();
+ gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
+
+ /* Create selection */
+ frame = gimp_frame_new (_("Selection"));
+ gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ data->store = gtk_list_store_new (1, G_TYPE_POINTER);
+ data->list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (data->store));
+ list = data->list;
+ g_object_unref (data->store);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (N_("#"),
+ renderer,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (column, renderer,
+ render_nr, data, NULL);
+ gtk_tree_view_column_set_min_width (column, 16);
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_alignment (column, 0.5);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("URL"));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start(column, renderer, FALSE);
+ gtk_tree_view_column_set_cell_data_func (column, renderer,
+ render_image, data, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, render_url, data,
+ NULL);
+ gtk_tree_view_column_set_min_width (column, 80);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_alignment (column, 0.5);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("ALT Text"), renderer,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, render_comment,
+ data, NULL);
+ gtk_tree_view_column_set_min_width (column, 64);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_alignment (column, 0.5);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("Target"), renderer,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (column, renderer,
+ render_target, data, NULL);
+ gtk_tree_view_column_set_min_width (column, 64);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+ gtk_tree_view_column_set_alignment (column, 0.5);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+
+ /* Create scrollable window */
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_set_size_request (swin, 16 + 80 + 2 * 64 + 16, -1);
+ gtk_container_add (GTK_CONTAINER(frame), swin);
+ gtk_widget_show (swin);
+
+ gtk_container_add (GTK_CONTAINER (swin), list);
+ gtk_widget_show (list);
+
+ /* Drop support */
+ gtk_drag_dest_set (list, GTK_DEST_DEFAULT_ALL, target_table, 2,
+ GDK_ACTION_COPY);
+ g_signal_connect (list, "drag-data-received", G_CALLBACK(handle_drop), NULL);
+
+ /* For handling doubleclick */
+
+ g_signal_connect (list, "button-press-event",
+ G_CALLBACK(button_press_cb), data);
+ g_signal_connect (list, "button-release-event",
+ G_CALLBACK(button_release_cb), data);
+
+ /* Callbacks we are interested in */
+ data->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+ gtk_tree_selection_set_mode (data->selection, GTK_SELECTION_MULTIPLE);
+ g_signal_connect (data->selection, "changed", G_CALLBACK(changed_cb), data);
+
+ /* Set object list callbacks we're interested in */
+ object_list_add_add_cb (object_list, object_added_cb, data);
+ object_list_add_update_cb (object_list, object_updated_cb, data);
+ object_list_add_remove_cb (object_list, object_removed_cb, data);
+ object_list_add_select_cb (object_list, object_selected_cb, data);
+ object_list_add_move_cb (object_list, object_moved_cb, data);
+
+ return data;
+}
+
+void
+selection_toggle_visibility(Selection_t *selection)
+{
+ /* Toggle */
+ selection->is_visible = ! selection->is_visible;
+
+ /* Adapt to new state */
+ gtk_widget_set_visible (selection->container,
+ selection->is_visible);
+}
+
+void
+selection_freeze(Selection_t *selection)
+{
+}
+
+void
+selection_thaw(Selection_t *selection)
+{
+}
diff --git a/plug-ins/imagemap/imap_selection.h b/plug-ins/imagemap/imap_selection.h
new file mode 100644
index 0000000..cb13afb
--- /dev/null
+++ b/plug-ins/imagemap/imap_selection.h
@@ -0,0 +1,64 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_SELECTION_H
+#define _IMAP_SELECTION_H
+
+#include "imap_command.h"
+#include "imap_object.h"
+
+typedef struct {
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+
+ GtkWidget *container;
+ GtkWidget *list;
+ GtkWidget *selected_child;
+ ObjectList_t *object_list;
+ gint selected_row;
+ gint nr_rows;
+ gboolean is_visible;
+ gboolean select_lock;
+ gboolean doubleclick;
+
+ CommandFactory_t cmd_move_up;
+ CommandFactory_t cmd_move_down;
+ CommandFactory_t cmd_delete;
+ CommandFactory_t cmd_edit;
+} Selection_t;
+
+Selection_t *make_selection(ObjectList_t *list);
+void selection_toggle_visibility(Selection_t *selection);
+void selection_freeze(Selection_t *selection);
+void selection_thaw(Selection_t *selection);
+
+#define selection_set_move_up_command(selection, command) \
+ ((selection)->cmd_move_up = (command))
+#define selection_set_move_down_command(selection, command) \
+ ((selection)->cmd_move_down = (command))
+#define selection_set_delete_command(selection, command) \
+ ((selection)->cmd_delete = (command))
+#define selection_set_edit_command(selection, command) \
+ ((selection)->cmd_edit = (command))
+
+#endif /* _IMAP_SELECTION_H */
+
diff --git a/plug-ins/imagemap/imap_settings.c b/plug-ins/imagemap/imap_settings.c
new file mode 100644
index 0000000..10a4a33
--- /dev/null
+++ b/plug-ins/imagemap/imap_settings.c
@@ -0,0 +1,188 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 "libgimp/gimpui.h"
+
+#include "imap_browse.h"
+#include "imap_main.h"
+#include "imap_settings.h"
+#include "imap_string.h"
+#include "imap_table.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+typedef struct {
+ DefaultDialog_t *dialog;
+ BrowseWidget_t *imagename;
+ GtkWidget *filename;
+ GtkWidget *title;
+ GtkWidget *author;
+ GtkWidget *default_url;
+ GtkWidget *ncsa;
+ GtkWidget *cern;
+ GtkWidget *csim;
+ GtkTextBuffer *description;
+} SettingsDialog_t;
+
+static MapFormat_t _map_format = CSIM;
+
+static void
+settings_ok_cb(gpointer data)
+{
+ SettingsDialog_t *param = (SettingsDialog_t*) data;
+ MapInfo_t *info = get_map_info();
+ gchar *description;
+ GtkTextIter start, end;
+
+ g_strreplace(&info->image_name, gtk_entry_get_text(
+ GTK_ENTRY(param->imagename->file)));
+ g_strreplace(&info->title, gtk_entry_get_text(GTK_ENTRY(param->title)));
+ g_strreplace(&info->author, gtk_entry_get_text(GTK_ENTRY(param->author)));
+ g_strreplace(&info->default_url,
+ gtk_entry_get_text(GTK_ENTRY(param->default_url)));
+ gtk_text_buffer_get_bounds(param->description, &start, &end);
+ description = gtk_text_buffer_get_text(param->description, &start, &end,
+ FALSE);
+ g_strreplace(&info->description, description);
+ g_free(description);
+
+ info->map_format = _map_format;
+}
+
+static void
+type_toggled_cb(GtkWidget *widget, gpointer data)
+{
+ if (gtk_widget_get_state (widget) & GTK_STATE_SELECTED)
+ _map_format = (MapFormat_t) data;
+}
+
+static SettingsDialog_t*
+create_settings_dialog(void)
+{
+ SettingsDialog_t *data = g_new(SettingsDialog_t, 1);
+ GtkWidget *table, *view, *frame, *hbox, *label, *swin;
+ DefaultDialog_t *dialog;
+
+ dialog = data->dialog = make_default_dialog(_("Settings for this Mapfile"));
+ default_dialog_set_ok_cb(dialog, settings_ok_cb, (gpointer) data);
+ table = default_dialog_add_table(dialog, 9, 2);
+
+ create_label_in_table(table, 0, 0, _("Filename:"));
+ data->filename = create_label_in_table(table, 0, 1, "");
+
+ create_label_in_table(table, 1, 0, _("Image name:"));
+ data->imagename = browse_widget_new(_("Select Image File"));
+ gtk_table_attach_defaults(GTK_TABLE(table), data->imagename->hbox, 1, 2,
+ 1, 2);
+
+ label = create_label_in_table(table, 2, 0, _("_Title:"));
+ data->title = create_entry_in_table(table, label, 2, 1);
+ label = create_label_in_table(table, 3, 0, _("Aut_hor:"));
+ data->author = create_entry_in_table(table, label, 3, 1);
+ label = create_label_in_table(table, 4, 0, _("Default _URL:"));
+ data->default_url = create_entry_in_table(table, label, 4, 1);
+ label = create_label_in_table(table, 5, 0, _("_Description:"));
+
+ data->description = gtk_text_buffer_new(NULL);
+
+ view = gtk_text_view_new_with_buffer(data->description);
+ gtk_widget_set_size_request(view, -1, 128);
+ gtk_widget_show(view);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), view);
+
+ swin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin),
+ GTK_SHADOW_IN);
+ gtk_table_attach(GTK_TABLE(table), swin, 1, 2, 5, 8,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_show(swin);
+ gtk_container_add(GTK_CONTAINER(swin), view);
+
+ frame = gimp_frame_new(_("Map File Format"));
+ gtk_widget_show(frame);
+ gtk_table_attach_defaults(GTK_TABLE(table), frame, 0, 2, 9, 10);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add(GTK_CONTAINER(frame), hbox);
+ gtk_widget_show(hbox);
+
+ data->ncsa = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_NCSA");
+ g_signal_connect(data->ncsa, "toggled",
+ G_CALLBACK(type_toggled_cb), (gpointer) NCSA);
+ gtk_box_pack_start(GTK_BOX(hbox), data->ncsa, FALSE, FALSE, 0);
+ gtk_widget_show(data->ncsa);
+
+ data->cern = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(data->ncsa), "C_ERN");
+ g_signal_connect(data->cern, "toggled",
+ G_CALLBACK(type_toggled_cb), (gpointer) CERN);
+ gtk_box_pack_start(GTK_BOX(hbox), data->cern, FALSE, FALSE, 0);
+ gtk_widget_show(data->cern);
+
+ data->csim = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(data->cern), "C_SIM");
+ g_signal_connect(data->csim, "toggled",
+ G_CALLBACK(type_toggled_cb), (gpointer) CSIM);
+ gtk_box_pack_start(GTK_BOX(hbox), data->csim, FALSE, FALSE, 0);
+ gtk_widget_show(data->csim);
+
+ return data;
+}
+
+void
+do_settings_dialog(void)
+{
+ static SettingsDialog_t *dialog;
+ const char *filename = get_filename();
+ MapInfo_t *info = get_map_info();
+
+ if (!dialog)
+ dialog = create_settings_dialog();
+
+ if (!filename)
+ filename = _("<Untitled>");
+
+ gtk_label_set_text(GTK_LABEL(dialog->filename), filename);
+ browse_widget_set_filename(dialog->imagename, info->image_name);
+ gtk_entry_set_text(GTK_ENTRY(dialog->title), info->title);
+ gtk_entry_set_text(GTK_ENTRY(dialog->author), info->author);
+ gtk_entry_set_text(GTK_ENTRY(dialog->default_url), info->default_url);
+
+ if (info->map_format == NCSA)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->ncsa), TRUE);
+ else if (info->map_format == CERN)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->cern), TRUE);
+ else
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->csim), TRUE);
+
+ gtk_widget_grab_focus(dialog->imagename->file);
+ default_dialog_show(dialog->dialog);
+
+ gtk_text_buffer_set_text (dialog->description, info->description, -1);
+}
diff --git a/plug-ins/imagemap/imap_settings.h b/plug-ins/imagemap/imap_settings.h
new file mode 100644
index 0000000..4b375d6
--- /dev/null
+++ b/plug-ins/imagemap/imap_settings.h
@@ -0,0 +1,28 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_SETTINGS_H
+#define _IMAP_SETTINGS_H
+
+void do_settings_dialog(void);
+
+#endif /* _IMAP_SETTINGS_H */
diff --git a/plug-ins/imagemap/imap_source.c b/plug-ins/imagemap/imap_source.c
new file mode 100644
index 0000000..40ba1b7
--- /dev/null
+++ b/plug-ins/imagemap/imap_source.c
@@ -0,0 +1,91 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "imap_default_dialog.h"
+#include "imap_main.h"
+#include "imap_source.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static void save_to_view (GtkTextBuffer *buffer,
+ const char *format,
+ ...) G_GNUC_PRINTF(2,3);
+
+static void
+save_to_view(GtkTextBuffer *buffer, const char* format, ...)
+{
+ va_list ap;
+ char scratch[1024];
+ GtkTextIter iter;
+
+ va_start(ap, format);
+ vsprintf(scratch, format, ap);
+ va_end(ap);
+
+ gtk_text_buffer_get_end_iter(buffer, &iter);
+ gtk_text_buffer_insert(buffer, &iter, scratch, -1);
+}
+
+void
+do_source_dialog(void)
+{
+ static DefaultDialog_t *dialog;
+ static GtkWidget *text;
+ static GtkTextBuffer *buffer;
+
+ if (!dialog)
+ {
+ GtkWidget *swin;
+
+ dialog = make_default_dialog(_("View Source"));
+ default_dialog_hide_cancel_button(dialog);
+ default_dialog_hide_apply_button(dialog);
+
+ buffer = gtk_text_buffer_new(NULL);
+
+ text = gtk_text_view_new_with_buffer(buffer);
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
+ gtk_widget_show(text);
+
+ swin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin),
+ GTK_SHADOW_IN);
+ gtk_widget_set_size_request(swin, 400, 300);
+ gtk_box_pack_start(GTK_BOX(dialog->vbox), swin, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_show(swin);
+ gtk_container_add(GTK_CONTAINER(swin), text);
+ }
+ gtk_text_buffer_set_text(buffer, "", -1);
+ dump_output(buffer, (OutputFunc_t) save_to_view);
+
+ default_dialog_show(dialog);
+}
diff --git a/plug-ins/imagemap/imap_source.h b/plug-ins/imagemap/imap_source.h
new file mode 100644
index 0000000..a090515
--- /dev/null
+++ b/plug-ins/imagemap/imap_source.h
@@ -0,0 +1,28 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_SOURCE_H
+#define _IMAP_SOURCE_H
+
+void do_source_dialog(void);
+
+#endif /* _IMAP_SOURCE_H */
diff --git a/plug-ins/imagemap/imap_statusbar.c b/plug-ins/imagemap/imap_statusbar.c
new file mode 100644
index 0000000..ca4bad8
--- /dev/null
+++ b/plug-ins/imagemap/imap_statusbar.c
@@ -0,0 +1,153 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include "imap_statusbar.h"
+#include "imap_stock.h"
+
+StatusBar_t*
+make_statusbar(GtkWidget *main_vbox, GtkWidget *window)
+{
+ StatusBar_t *statusbar = g_new(StatusBar_t, 1);
+ GtkWidget *hbox, *iconw;
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_box_pack_start(GTK_BOX(main_vbox), hbox, FALSE, FALSE, 0);
+
+ /* Status info */
+ statusbar->status = gtk_statusbar_new();
+ statusbar->status_id = gtk_statusbar_get_context_id(
+ GTK_STATUSBAR(statusbar->status), "general_status");
+ gtk_box_pack_start(GTK_BOX(hbox), statusbar->status, TRUE, TRUE, 0);
+ gtk_widget_show(statusbar->status);
+
+ /* (x, y) coordinate */
+ iconw = gtk_image_new_from_stock(IMAP_STOCK_COORD,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+
+ gtk_box_pack_start(GTK_BOX(hbox), iconw, FALSE, FALSE, 10);
+ gtk_widget_show(iconw);
+
+ statusbar->xy = gtk_entry_new();
+ gtk_widget_set_size_request(statusbar->xy, 96, -1);
+ gtk_editable_set_editable(GTK_EDITABLE(statusbar->xy), FALSE);
+ gtk_widget_set_can_focus (statusbar->xy, FALSE);
+ gtk_box_pack_start(GTK_BOX(hbox), statusbar->xy, FALSE, FALSE, 0);
+ gtk_widget_show(statusbar->xy);
+
+ /* Dimension info */
+ iconw = gtk_image_new_from_stock(IMAP_STOCK_DIMENSION,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_box_pack_start(GTK_BOX(hbox), iconw, FALSE, FALSE, 10);
+ gtk_widget_show(iconw);
+
+ statusbar->dimension = gtk_entry_new();
+ gtk_widget_set_size_request(statusbar->dimension, 96, -1);
+ gtk_editable_set_editable(GTK_EDITABLE(statusbar->dimension), FALSE);
+ gtk_widget_set_can_focus (statusbar->dimension, FALSE);
+ gtk_box_pack_start(GTK_BOX(hbox), statusbar->dimension, FALSE, FALSE, 0);
+ gtk_widget_show(statusbar->dimension);
+
+ /* Zoom info */
+ statusbar->zoom = gtk_statusbar_new();
+ gtk_widget_set_size_request(statusbar->zoom, 48, -1);
+ statusbar->zoom_id = gtk_statusbar_get_context_id(
+ GTK_STATUSBAR(statusbar->zoom), "zoom_status");
+ gtk_box_pack_start(GTK_BOX(hbox), statusbar->zoom, FALSE, FALSE, 5);
+ gtk_widget_show(statusbar->zoom);
+
+ gtk_widget_show(hbox);
+
+ return statusbar;
+}
+
+void
+statusbar_set_status(StatusBar_t *statusbar, const gchar *format, ...)
+{
+ va_list ap;
+ char *str;
+
+ va_start(ap, format);
+ str = g_strdup_vprintf (format, ap);
+ va_end(ap);
+
+ statusbar_clear_status(statusbar);
+ statusbar->message_id =
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar->status),
+ statusbar->status_id, str);
+ g_free (str);
+}
+
+void
+statusbar_clear_status(StatusBar_t *statusbar)
+{
+ if (statusbar->message_id)
+ gtk_statusbar_remove(GTK_STATUSBAR(statusbar->status),
+ statusbar->status_id,
+ statusbar->message_id);
+}
+
+void
+statusbar_set_xy(StatusBar_t *statusbar, gint x, gint y)
+{
+ char scratch[16];
+
+ sprintf(scratch, "%d, %d", (int) x, (int) y);
+ gtk_entry_set_text(GTK_ENTRY(statusbar->xy), scratch);
+}
+
+void statusbar_clear_xy(StatusBar_t *statusbar)
+{
+ gtk_entry_set_text(GTK_ENTRY(statusbar->xy), "");
+}
+
+void
+statusbar_set_dimension(StatusBar_t *statusbar, gint w, gint h)
+{
+ gchar scratch[16];
+
+ g_snprintf (scratch, sizeof (scratch), "%d × %d", (gint) w, (gint) h);
+ gtk_entry_set_text(GTK_ENTRY(statusbar->dimension), scratch);
+}
+
+void
+statusbar_clear_dimension(StatusBar_t *statusbar)
+{
+ gtk_entry_set_text(GTK_ENTRY(statusbar->dimension), "");
+}
+
+void
+statusbar_set_zoom(StatusBar_t *statusbar, gint factor)
+{
+ char scratch[16];
+
+ sprintf(scratch, "1:%d", factor);
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar->zoom), statusbar->zoom_id,
+ scratch);
+}
diff --git a/plug-ins/imagemap/imap_statusbar.h b/plug-ins/imagemap/imap_statusbar.h
new file mode 100644
index 0000000..6b1a87b
--- /dev/null
+++ b/plug-ins/imagemap/imap_statusbar.h
@@ -0,0 +1,47 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2003 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_STATUSBAR_H
+#define _IMAP_STATUSBAR_H
+
+typedef struct {
+ GtkWidget *status;
+ GtkWidget *xy;
+ GtkWidget *dimension;
+ GtkWidget *zoom;
+
+ gint status_id;
+ gint message_id;
+
+ gint zoom_id;
+} StatusBar_t;
+
+StatusBar_t *make_statusbar(GtkWidget *main_vbox, GtkWidget *window);
+void statusbar_set_status(StatusBar_t *statusbar, const gchar *format, ...) G_GNUC_PRINTF(2,3);
+void statusbar_clear_status(StatusBar_t *statusbar);
+void statusbar_set_xy(StatusBar_t *statusbar, gint x, gint y);
+void statusbar_clear_xy(StatusBar_t *statusbar);
+void statusbar_set_dimension(StatusBar_t *statusbar, gint w, gint h);
+void statusbar_clear_dimension(StatusBar_t *statusbar);
+void statusbar_set_zoom(StatusBar_t *statusbar, gint factor);
+
+#endif /* _IMAP_STATUSBAR_H */
diff --git a/plug-ins/imagemap/imap_stock.c b/plug-ins/imagemap/imap_stock.c
new file mode 100644
index 0000000..4c3fedd
--- /dev/null
+++ b/plug-ins/imagemap/imap_stock.c
@@ -0,0 +1,89 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2005 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 <gtk/gtk.h>
+
+#include "imap_stock.h"
+
+#include "images/imap-stock-pixbufs.h"
+
+static GtkIconFactory *imap_icon_factory = NULL;
+
+static GtkStockItem imap_stock_items[] =
+{
+ { IMAP_STOCK_CIRCLE, NULL, 0, 0, NULL },
+ { IMAP_STOCK_COORD, NULL, 0, 0, NULL },
+ { IMAP_STOCK_DIMENSION, NULL, 0, 0, NULL },
+ { IMAP_STOCK_JAVA, NULL, 0, 0, NULL },
+ { IMAP_STOCK_POLYGON, NULL, 0, 0, NULL },
+ { IMAP_STOCK_RECTANGLE, NULL, 0, 0, NULL },
+ { IMAP_STOCK_TO_BACK, NULL, 0, 0, NULL },
+ { IMAP_STOCK_TO_FRONT, NULL, 0, 0, NULL }
+ };
+
+static void
+add_stock_icon (const gchar *stock_id,
+ const guint8 *inline_data)
+{
+ GtkIconSource *source;
+ GtkIconSet *set;
+ GdkPixbuf *pixbuf;
+
+ source = gtk_icon_source_new ();
+
+ gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_icon_source_set_size_wildcarded (source, TRUE);
+
+ pixbuf = gdk_pixbuf_new_from_inline (-1, inline_data, FALSE, NULL);
+ gtk_icon_source_set_pixbuf (source, pixbuf);
+ g_object_unref (pixbuf);
+
+ set = gtk_icon_set_new ();
+
+ gtk_icon_set_add_source (set, source);
+ gtk_icon_source_free (source);
+
+ gtk_icon_factory_add (imap_icon_factory, stock_id, set);
+
+ gtk_icon_set_unref (set);
+}
+
+void
+init_stock_icons (void)
+{
+ imap_icon_factory = gtk_icon_factory_new ();
+
+ add_stock_icon (IMAP_STOCK_CIRCLE, stock_circle);
+ add_stock_icon (IMAP_STOCK_COORD, stock_coord);
+ add_stock_icon (IMAP_STOCK_DIMENSION, stock_dimension);
+ add_stock_icon (IMAP_STOCK_JAVA, stock_java);
+ add_stock_icon (IMAP_STOCK_POLYGON, stock_polygon);
+ add_stock_icon (IMAP_STOCK_RECTANGLE, stock_rectangle);
+ add_stock_icon (IMAP_STOCK_TO_BACK, stock_to_back);
+ add_stock_icon (IMAP_STOCK_TO_FRONT, stock_to_front);
+
+ gtk_icon_factory_add_default (imap_icon_factory);
+
+ gtk_stock_add_static (imap_stock_items, G_N_ELEMENTS (imap_stock_items));
+}
diff --git a/plug-ins/imagemap/imap_stock.h b/plug-ins/imagemap/imap_stock.h
new file mode 100644
index 0000000..5587b91
--- /dev/null
+++ b/plug-ins/imagemap/imap_stock.h
@@ -0,0 +1,39 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2004 Maurits Rijk m.rijk@chello.nl
+ *
+ * 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 _IMAP_STOCK_H
+#define _IMAP_STOCK_H
+
+#define IMAP_STOCK_ARROW "imap-arrow"
+#define IMAP_STOCK_CIRCLE "imap-circle"
+#define IMAP_STOCK_COORD "imap-coord"
+#define IMAP_STOCK_DIMENSION "imap-dimension"
+#define IMAP_STOCK_JAVA "imap-java"
+#define IMAP_STOCK_LINK "imap-link"
+#define IMAP_STOCK_POLYGON "imap-polygon"
+#define IMAP_STOCK_RECTANGLE "imap-rectangle"
+#define IMAP_STOCK_TO_BACK "imap-to-back"
+#define IMAP_STOCK_TO_FRONT "imap-to-front"
+
+void init_stock_icons(void);
+
+#endif /* _IMAP_STOCK_H */
diff --git a/plug-ins/imagemap/imap_string.c b/plug-ins/imagemap/imap_string.c
new file mode 100644
index 0000000..5f3b31c
--- /dev/null
+++ b/plug-ins/imagemap/imap_string.c
@@ -0,0 +1,37 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <glib.h>
+
+#include "imap_string.h"
+
+gchar*
+g_strreplace(gchar **old_str, const gchar *new_str)
+{
+ if (*old_str != new_str) {
+ g_free(*old_str);
+ *old_str = g_strdup(new_str);
+ }
+ return *old_str;
+}
diff --git a/plug-ins/imagemap/imap_string.h b/plug-ins/imagemap/imap_string.h
new file mode 100644
index 0000000..c878131
--- /dev/null
+++ b/plug-ins/imagemap/imap_string.h
@@ -0,0 +1,28 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_STRING_H
+#define _IMAP_STRING_H
+
+gchar *g_strreplace(gchar **old_str, const gchar *new_str);
+
+#endif /* _IMAP_STRING_H */
diff --git a/plug-ins/imagemap/imap_table.c b/plug-ins/imagemap/imap_table.c
new file mode 100644
index 0000000..d72a478
--- /dev/null
+++ b/plug-ins/imagemap/imap_table.c
@@ -0,0 +1,81 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <libgimp/gimpui.h>
+
+#include "imap_table.h"
+
+static GtkWidget*
+add_widget_to_table(GtkWidget *table, int row, int col, GtkWidget *w)
+{
+ gtk_table_attach_defaults(GTK_TABLE(table), w, col, col + 1, row, row + 1);
+ gtk_widget_show(w);
+ return w;
+}
+
+GtkWidget*
+create_spin_button_in_table(GtkWidget *table, GtkWidget *label,
+ int row, int col, int value, int min, int max)
+{
+ GtkObject *adj = gtk_adjustment_new(value, min, max, 1, 10, 0);
+ GtkWidget *button = gimp_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
+ gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(button), TRUE);
+ if (label)
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), button);
+ return add_widget_to_table(table, row, col, button);
+}
+
+GtkWidget*
+create_check_button_in_table(GtkWidget *table, int row, int col,
+ const char *text)
+{
+ GtkWidget *button = gtk_check_button_new_with_mnemonic(text);
+ return add_widget_to_table(table, row, col, button);
+}
+
+GtkWidget*
+create_radio_button_in_table(GtkWidget *table, GSList *group,
+ int row, int col, const char *text)
+{
+ GtkWidget *button = gtk_radio_button_new_with_mnemonic(group, text);
+ return add_widget_to_table(table, row, col, button);
+}
+
+GtkWidget*
+create_label_in_table(GtkWidget *table, int row, int col, const char *text)
+{
+ GtkWidget *label = gtk_label_new_with_mnemonic(text);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ return add_widget_to_table(table, row, col, label);
+}
+
+GtkWidget*
+create_entry_in_table(GtkWidget *table, GtkWidget *label, int row, int col)
+{
+ GtkWidget *entry = gtk_entry_new();
+ if (label)
+ gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+ return add_widget_to_table(table, row, col, entry);
+}
diff --git a/plug-ins/imagemap/imap_table.h b/plug-ins/imagemap/imap_table.h
new file mode 100644
index 0000000..5b6a855
--- /dev/null
+++ b/plug-ins/imagemap/imap_table.h
@@ -0,0 +1,39 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-2002 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_TABLE_H
+#define _IMAP_TABLE_H
+
+GtkWidget *create_spin_button_in_table(GtkWidget *table, GtkWidget *label,
+ int row, int col,
+ int value, int min, int max);
+GtkWidget *create_check_button_in_table(GtkWidget *table, int row, int col,
+ const char *text);
+GtkWidget *create_radio_button_in_table(GtkWidget *table, GSList *group,
+ int row, int col, const char *text);
+GtkWidget *create_label_in_table(GtkWidget *table, int row, int col,
+ const char *text);
+GtkWidget *create_entry_in_table(GtkWidget *table, GtkWidget *label, int row,
+ int col);
+
+#endif /* _IMAP_TABLE_H */
+
diff --git a/plug-ins/imagemap/imap_taglist.c b/plug-ins/imagemap/imap_taglist.c
new file mode 100644
index 0000000..9b03c9d
--- /dev/null
+++ b/plug-ins/imagemap/imap_taglist.c
@@ -0,0 +1,126 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 <glib.h>
+
+#include "imap_string.h"
+#include "imap_taglist.h"
+
+static Tag_t*
+tag_create(const gchar *name, const gchar *value)
+{
+ Tag_t *tag = g_new(Tag_t, 1);
+ tag->name = g_strdup(name);
+ tag->value = g_strdup(value);
+ return tag;
+}
+
+static Tag_t*
+tag_clone(Tag_t *src)
+{
+ return tag_create(src->name, src->value);
+}
+
+static void
+tag_destruct(Tag_t *tag)
+{
+ g_free(tag->name);
+ g_free(tag->value);
+ g_free(tag);
+}
+
+static void
+tag_write(Tag_t *tag)
+{
+ printf("\"%s\"=\"%s\"\n", tag->name, tag->value);
+}
+
+TagList_t*
+taglist_create(void)
+{
+ TagList_t *tlist = g_new(TagList_t, 1);
+ tlist->list = NULL;
+ return tlist;
+}
+
+TagList_t*
+taglist_clone(TagList_t *src)
+{
+ return taglist_copy(src, taglist_create());
+}
+
+static void
+taglist_remove_all(TagList_t *tlist)
+{
+ GList *p;
+ for (p = tlist->list; p; p = p->next)
+ tag_destruct((Tag_t*) p->data);
+ g_list_free(tlist->list);
+ tlist->list = NULL;
+}
+
+TagList_t*
+taglist_copy(TagList_t *src, TagList_t *des)
+{
+ GList *p;
+
+ taglist_remove_all(des);
+ for (p = src->list; p; p = p->next)
+ des->list = g_list_append(des->list, tag_clone((Tag_t*) p->data));
+ return des;
+}
+
+void
+taglist_destruct(TagList_t *tlist)
+{
+ taglist_remove_all(tlist);
+ g_free(tlist);
+}
+
+void
+taglist_set(TagList_t *tlist, const gchar *name, const gchar *value)
+{
+ GList *p;
+ Tag_t *tag;
+
+ for (p = tlist->list; p; p = p->next) {
+ tag = (Tag_t*) p->data;
+ if (!g_ascii_strcasecmp(tag->name, name)) {
+ g_strreplace(&tag->value, value);
+ return;
+ }
+ }
+ /* Tag not found, add a new tag */
+ tlist->list = g_list_append(tlist->list, tag_create(name, value));
+}
+
+void
+taglist_write(TagList_t *tlist)
+{
+ GList *p;
+ for (p = tlist->list; p; p = p->next)
+ tag_write((Tag_t*) p->data);
+}
diff --git a/plug-ins/imagemap/imap_taglist.h b/plug-ins/imagemap/imap_taglist.h
new file mode 100644
index 0000000..c68ef51
--- /dev/null
+++ b/plug-ins/imagemap/imap_taglist.h
@@ -0,0 +1,44 @@
+/*
+ * This is a plug-in for GIMP.
+ *
+ * Generates clickable image maps.
+ *
+ * Copyright (C) 1998-1999 Maurits Rijk lpeek.mrijk@consunet.nl
+ *
+ * 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 _IMAP_TAGLIST_H
+#define _IMAP_TAGLIST_H
+
+#include <glib.h>
+
+typedef struct {
+ gchar *name;
+ gchar *value;
+} Tag_t;
+
+typedef struct {
+ GList *list;
+} TagList_t;
+
+TagList_t *taglist_create(void);
+TagList_t *taglist_clone(TagList_t *src);
+TagList_t *taglist_copy(TagList_t *src, TagList_t *des);
+void taglist_destruct(TagList_t *tlist);
+void taglist_set(TagList_t *tlist, const gchar *id, const gchar *value);
+void taglist_write(TagList_t *tlist);
+
+#endif /* _IMAP_TAGLIST_H */