gimp/plug-ins/imagemap/imap_csim.y

397 lines
8.1 KiB
Plaintext
Raw Normal View History

1999-09-07 08:03:20 +08:00
%{
/*
* This is a plug-in for GIMP.
1999-09-07 08:03:20 +08:00
*
* Generates clickable image maps.
*
* Copyright (C) 1998-2005 Maurits Rijk lpeek.mrijk@consunet.nl
1999-09-07 08:03:20 +08:00
*
* This program is free software: you can redistribute it and/or modify
1999-09-07 08:03:20 +08:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
1999-09-07 08:03:20 +08:00
* (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/>.
1999-09-07 08:03:20 +08:00
*
*/
#include <stdlib.h>
#include <string.h>
1999-09-07 08:03:20 +08:00
#include <glib/gstdio.h>
#include <gtk/gtk.h>
1999-09-07 08:03:20 +08:00
#include "imap_circle.h"
#include "imap_file.h"
#include "imap_main.h"
#include "imap_polygon.h"
#include "imap_rectangle.h"
#include "imap_string.h"
2011-04-23 09:32:02 +08:00
extern int csim_lex(void);
extern int csim_restart(FILE *csim_in);
1999-09-07 08:03:20 +08:00
static void csim_error(char* s);
static gchar * unescape_text(gchar *input);
1999-09-07 08:03:20 +08:00
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;
1999-09-07 08:03:20 +08:00
}
%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
1999-09-07 08:03:20 +08:00
%%
csim_file : image start_map comment_lines area_list end_map
;
2002-12-21 20:53:28 +08:00
image : '<' IMG SRC '=' STRING image_tags xhtml_close
1999-09-07 08:03:20 +08:00
{
g_strreplace(&_map_info->image_name, $5);
g_free ($5);
1999-09-07 08:03:20 +08:00
}
;
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); }
1999-09-07 08:03:20 +08:00
;
image_width : WIDTH '=' integer_value
1999-09-07 08:03:20 +08:00
{
_map_info->old_image_width = $3;
1999-09-07 08:03:20 +08:00
}
;
image_height : HEIGHT '=' integer_value
{
_map_info->old_image_height = $3;
}
;
integer_value : FLOAT
{
$$ = (gint) $1;
}
| STRING
1999-09-07 08:03:20 +08:00
{
$$ = (gint) g_ascii_strtod ($1, NULL);
g_free ($1);
1999-09-07 08:03:20 +08:00
}
;
start_map : '<' START_MAP NAME '=' STRING '>'
{
g_strreplace(&_map_info->title, $5);
g_free ($5);
1999-09-07 08:03:20 +08:00
}
;
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);
1999-09-07 08:03:20 +08:00
}
;
author_line : AUTHOR STRING END_COMMENT
{
g_strreplace(&_map_info->author, $2);
g_free ($2);
1999-09-07 08:03:20 +08:00
}
;
description_line: DESCRIPTION STRING END_COMMENT
{
gchar *description;
description = g_strconcat(_map_info->description, $2, "\n",
1999-09-07 08:03:20 +08:00
NULL);
g_strreplace(&_map_info->description, description);
g_free ($2);
1999-09-07 08:03:20 +08:00
}
;
area_list : /* empty */
| area_list area
;
2002-12-21 20:53:28 +08:00
area : '<' AREA tag_list xhtml_close
1999-09-07 08:03:20 +08:00
{
if (current_type != UNDEFINED)
add_shape(current_object);
}
;
2002-12-21 20:53:28 +08:00
xhtml_close : '>'
| '/' '>'
2002-12-21 20:53:28 +08:00
;
1999-09-07 08:03:20 +08:00
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
{
link the app in a different order as some init functions are called from 2001-10-19 Michael Natterer <mitch@gimp.org> * app/Makefile.am: link the app in a different order as some init functions are called from core/gimp.c instead of app_procs.c now. * app/app_procs.[ch]: made app_init_update_status() private and pass it as callback to various init functions. * app/plug_in.[ch]: plug_in_init() take "gimp" and "status_callback" parameters. * app/undo.c: use "gimage->gimp" instead of "the_gimp", don't include "app_procs.h". * app/core/core-types.h: added "GimpInitStatusFunc" typedef. * app/core/gimp.[ch]: gimp_initialize() and gimp_restore() now take a "status_callback" as parameter. Don't include "app_procs.h". * app/core/gimpmodules.c: putting the modules in a strong container was a bad idea because it may be impossible to finalize a GimpModuleInfo object belonging to a stalled module. * app/gui/color-area.c: use G_N_ELEMENTS(). * app/gui/session.c: don't call app_init_update_status() and don't include "app_procs.h" because this happens after the splash is hidden. * tools/pdbgen/app.pl * app/pdb/internal_procs.[ch]: pass a "status_callback" to internal_procs_init(), don't include "app_procs.h". * plug-ins/Makefile.am: build gfig, gimpressionist and imagemap again. * plug-ins/MapObject/mapobject_preview.c * plug-ins/MapObject/mapobject_ui.c: s/gdk_image_unref/g_object_unref/ * plug-ins/gfig/gfig.c * plug-ins/gimpressionist/brush.c * plug-ins/gimpressionist/gimpressionist.c * plug-ins/gimpressionist/ppmtool.[ch] * plug-ins/gimpressionist/presets.c * plug-ins/imagemap/imap_browse.[ch] * plug-ins/imagemap/imap_csim.y * plug-ins/imagemap/imap_edit_area_info.c * plug-ins/imagemap/imap_file.c * plug-ins/imagemap/imap_main.c * plug-ins/imagemap/imap_menu.c * plug-ins/imagemap/imap_polygon.c * plug-ins/imagemap/imap_popup.c * plug-ins/imagemap/imap_preferences.c * plug-ins/imagemap/imap_taglist.c * plug-ins/imagemap/imap_tools.c: ported to current GLib/Gtk+. * plug-ins/gap/gap_arr_dialog.c * plug-ins/gap/gap_decode_xanim.c * plug-ins/gap/gap_filter_foreach.c * plug-ins/gap/gap_filter_main.c * plug-ins/gap/gap_frontends_main.c * plug-ins/gap/gap_lib.c * plug-ins/gap/gap_main.c * plug-ins/gap/gap_mod_layer.c * plug-ins/gap/gap_mov_dialog.c * plug-ins/gap/gap_navigator_dialog.c * plug-ins/gap/resize.c: half-way fixed this one too but I'm not willing to fix tons of duplicated and deprecated app/ code...
2001-10-20 00:41:09 +08:00
if (!g_ascii_strcasecmp($3, "RECT")) {
1999-09-07 08:03:20 +08:00
current_object = create_rectangle(0, 0, 0, 0);
current_type = RECTANGLE;
link the app in a different order as some init functions are called from 2001-10-19 Michael Natterer <mitch@gimp.org> * app/Makefile.am: link the app in a different order as some init functions are called from core/gimp.c instead of app_procs.c now. * app/app_procs.[ch]: made app_init_update_status() private and pass it as callback to various init functions. * app/plug_in.[ch]: plug_in_init() take "gimp" and "status_callback" parameters. * app/undo.c: use "gimage->gimp" instead of "the_gimp", don't include "app_procs.h". * app/core/core-types.h: added "GimpInitStatusFunc" typedef. * app/core/gimp.[ch]: gimp_initialize() and gimp_restore() now take a "status_callback" as parameter. Don't include "app_procs.h". * app/core/gimpmodules.c: putting the modules in a strong container was a bad idea because it may be impossible to finalize a GimpModuleInfo object belonging to a stalled module. * app/gui/color-area.c: use G_N_ELEMENTS(). * app/gui/session.c: don't call app_init_update_status() and don't include "app_procs.h" because this happens after the splash is hidden. * tools/pdbgen/app.pl * app/pdb/internal_procs.[ch]: pass a "status_callback" to internal_procs_init(), don't include "app_procs.h". * plug-ins/Makefile.am: build gfig, gimpressionist and imagemap again. * plug-ins/MapObject/mapobject_preview.c * plug-ins/MapObject/mapobject_ui.c: s/gdk_image_unref/g_object_unref/ * plug-ins/gfig/gfig.c * plug-ins/gimpressionist/brush.c * plug-ins/gimpressionist/gimpressionist.c * plug-ins/gimpressionist/ppmtool.[ch] * plug-ins/gimpressionist/presets.c * plug-ins/imagemap/imap_browse.[ch] * plug-ins/imagemap/imap_csim.y * plug-ins/imagemap/imap_edit_area_info.c * plug-ins/imagemap/imap_file.c * plug-ins/imagemap/imap_main.c * plug-ins/imagemap/imap_menu.c * plug-ins/imagemap/imap_polygon.c * plug-ins/imagemap/imap_popup.c * plug-ins/imagemap/imap_preferences.c * plug-ins/imagemap/imap_taglist.c * plug-ins/imagemap/imap_tools.c: ported to current GLib/Gtk+. * plug-ins/gap/gap_arr_dialog.c * plug-ins/gap/gap_decode_xanim.c * plug-ins/gap/gap_filter_foreach.c * plug-ins/gap/gap_filter_main.c * plug-ins/gap/gap_frontends_main.c * plug-ins/gap/gap_lib.c * plug-ins/gap/gap_main.c * plug-ins/gap/gap_mod_layer.c * plug-ins/gap/gap_mov_dialog.c * plug-ins/gap/gap_navigator_dialog.c * plug-ins/gap/resize.c: half-way fixed this one too but I'm not willing to fix tons of duplicated and deprecated app/ code...
2001-10-20 00:41:09 +08:00
} else if (!g_ascii_strcasecmp($3, "CIRCLE")) {
1999-09-07 08:03:20 +08:00
current_object = create_circle(0, 0, 0);
current_type = CIRCLE;
link the app in a different order as some init functions are called from 2001-10-19 Michael Natterer <mitch@gimp.org> * app/Makefile.am: link the app in a different order as some init functions are called from core/gimp.c instead of app_procs.c now. * app/app_procs.[ch]: made app_init_update_status() private and pass it as callback to various init functions. * app/plug_in.[ch]: plug_in_init() take "gimp" and "status_callback" parameters. * app/undo.c: use "gimage->gimp" instead of "the_gimp", don't include "app_procs.h". * app/core/core-types.h: added "GimpInitStatusFunc" typedef. * app/core/gimp.[ch]: gimp_initialize() and gimp_restore() now take a "status_callback" as parameter. Don't include "app_procs.h". * app/core/gimpmodules.c: putting the modules in a strong container was a bad idea because it may be impossible to finalize a GimpModuleInfo object belonging to a stalled module. * app/gui/color-area.c: use G_N_ELEMENTS(). * app/gui/session.c: don't call app_init_update_status() and don't include "app_procs.h" because this happens after the splash is hidden. * tools/pdbgen/app.pl * app/pdb/internal_procs.[ch]: pass a "status_callback" to internal_procs_init(), don't include "app_procs.h". * plug-ins/Makefile.am: build gfig, gimpressionist and imagemap again. * plug-ins/MapObject/mapobject_preview.c * plug-ins/MapObject/mapobject_ui.c: s/gdk_image_unref/g_object_unref/ * plug-ins/gfig/gfig.c * plug-ins/gimpressionist/brush.c * plug-ins/gimpressionist/gimpressionist.c * plug-ins/gimpressionist/ppmtool.[ch] * plug-ins/gimpressionist/presets.c * plug-ins/imagemap/imap_browse.[ch] * plug-ins/imagemap/imap_csim.y * plug-ins/imagemap/imap_edit_area_info.c * plug-ins/imagemap/imap_file.c * plug-ins/imagemap/imap_main.c * plug-ins/imagemap/imap_menu.c * plug-ins/imagemap/imap_polygon.c * plug-ins/imagemap/imap_popup.c * plug-ins/imagemap/imap_preferences.c * plug-ins/imagemap/imap_taglist.c * plug-ins/imagemap/imap_tools.c: ported to current GLib/Gtk+. * plug-ins/gap/gap_arr_dialog.c * plug-ins/gap/gap_decode_xanim.c * plug-ins/gap/gap_filter_foreach.c * plug-ins/gap/gap_filter_main.c * plug-ins/gap/gap_frontends_main.c * plug-ins/gap/gap_lib.c * plug-ins/gap/gap_main.c * plug-ins/gap/gap_mod_layer.c * plug-ins/gap/gap_mov_dialog.c * plug-ins/gap/gap_navigator_dialog.c * plug-ins/gap/resize.c: half-way fixed this one too but I'm not willing to fix tons of duplicated and deprecated app/ code...
2001-10-20 00:41:09 +08:00
} else if (!g_ascii_strcasecmp($3, "POLY")) {
1999-09-07 08:03:20 +08:00
current_object = create_polygon(NULL);
current_type = POLYGON;
link the app in a different order as some init functions are called from 2001-10-19 Michael Natterer <mitch@gimp.org> * app/Makefile.am: link the app in a different order as some init functions are called from core/gimp.c instead of app_procs.c now. * app/app_procs.[ch]: made app_init_update_status() private and pass it as callback to various init functions. * app/plug_in.[ch]: plug_in_init() take "gimp" and "status_callback" parameters. * app/undo.c: use "gimage->gimp" instead of "the_gimp", don't include "app_procs.h". * app/core/core-types.h: added "GimpInitStatusFunc" typedef. * app/core/gimp.[ch]: gimp_initialize() and gimp_restore() now take a "status_callback" as parameter. Don't include "app_procs.h". * app/core/gimpmodules.c: putting the modules in a strong container was a bad idea because it may be impossible to finalize a GimpModuleInfo object belonging to a stalled module. * app/gui/color-area.c: use G_N_ELEMENTS(). * app/gui/session.c: don't call app_init_update_status() and don't include "app_procs.h" because this happens after the splash is hidden. * tools/pdbgen/app.pl * app/pdb/internal_procs.[ch]: pass a "status_callback" to internal_procs_init(), don't include "app_procs.h". * plug-ins/Makefile.am: build gfig, gimpressionist and imagemap again. * plug-ins/MapObject/mapobject_preview.c * plug-ins/MapObject/mapobject_ui.c: s/gdk_image_unref/g_object_unref/ * plug-ins/gfig/gfig.c * plug-ins/gimpressionist/brush.c * plug-ins/gimpressionist/gimpressionist.c * plug-ins/gimpressionist/ppmtool.[ch] * plug-ins/gimpressionist/presets.c * plug-ins/imagemap/imap_browse.[ch] * plug-ins/imagemap/imap_csim.y * plug-ins/imagemap/imap_edit_area_info.c * plug-ins/imagemap/imap_file.c * plug-ins/imagemap/imap_main.c * plug-ins/imagemap/imap_menu.c * plug-ins/imagemap/imap_polygon.c * plug-ins/imagemap/imap_popup.c * plug-ins/imagemap/imap_preferences.c * plug-ins/imagemap/imap_taglist.c * plug-ins/imagemap/imap_tools.c: ported to current GLib/Gtk+. * plug-ins/gap/gap_arr_dialog.c * plug-ins/gap/gap_decode_xanim.c * plug-ins/gap/gap_filter_foreach.c * plug-ins/gap/gap_filter_main.c * plug-ins/gap/gap_frontends_main.c * plug-ins/gap/gap_lib.c * plug-ins/gap/gap_main.c * plug-ins/gap/gap_mod_layer.c * plug-ins/gap/gap_mov_dialog.c * plug-ins/gap/gap_navigator_dialog.c * plug-ins/gap/resize.c: half-way fixed this one too but I'm not willing to fix tons of duplicated and deprecated app/ code...
2001-10-20 00:41:09 +08:00
} else if (!g_ascii_strcasecmp($3, "DEFAULT")) {
1999-09-07 08:03:20 +08:00
current_type = UNDEFINED;
}
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
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);
1999-09-07 08:03:20 +08:00
}
/* Remove last point if duplicate */
first = (GdkPoint*) points->data;
polygon->points = points;
1999-09-07 08:03:20 +08:00
if (first->x == point->x && first->y == point->y)
polygon_remove_last_point(polygon);
polygon->points = points;
}
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
href_tag : HREF '=' STRING
{
if (current_type == UNDEFINED) {
g_strreplace(&_map_info->default_url, $3);
} else {
object_set_url(current_object, unescape_text($3));
1999-09-07 08:03:20 +08:00
}
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
nohref_tag : NOHREF optional_value
{
}
;
optional_value : /* Empty */
| '=' STRING
1999-09-07 08:03:20 +08:00
{
g_free ($2);
1999-09-07 08:03:20 +08:00
}
;
alt_tag : ALT '=' STRING
{
object_set_comment(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
target_tag : TARGET '=' STRING
{
object_set_target(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
onmouseover_tag : ONMOUSEOVER '=' STRING
{
object_set_mouse_over(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
onmouseout_tag : ONMOUSEOUT '=' STRING
{
object_set_mouse_out(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
onfocus_tag : ONFOCUS '=' STRING
{
object_set_focus(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
onblur_tag : ONBLUR '=' STRING
{
object_set_blur(current_object, unescape_text($3));
g_free ($3);
1999-09-07 08:03:20 +08:00
}
;
end_map : '<' END_MAP '>'
;
%%
static void
1999-09-07 08:03:20 +08:00
csim_error(char* s)
{
extern FILE *csim_in;
csim_restart(csim_in);
}
gboolean
load_csim (const char* filename)
1999-09-07 08:03:20 +08:00
{
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;
1999-09-07 08:03:20 +08:00
}
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;
}