]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
Initial scripted plugin support
authorCharlie Brej <cbrej@cs.man.ac.uk>
Fri, 12 Jun 2009 17:04:25 +0000 (18:04 +0100)
committerRay Strode <rstrode@redhat.com>
Fri, 24 Jul 2009 13:30:05 +0000 (09:30 -0400)
This is an initial support for the scripted plugin. There are _many_ FIXMEs
and the whole code is reather unstable. The formatting is completely incorrect
and will be changed soon. There are scripts which are converted using a perl
to an C embeddable string.

32 files changed:
configure.ac
src/plugins/splash/Makefile.am
src/plugins/splash/script/Makefile.am [new file with mode: 0644]
src/plugins/splash/script/plugin.c [new file with mode: 0644]
src/plugins/splash/script/plugin.h [new file with mode: 0644]
src/plugins/splash/script/ply-scan.c [new file with mode: 0644]
src/plugins/splash/script/ply-scan.h [new file with mode: 0644]
src/plugins/splash/script/script-execute.c [new file with mode: 0644]
src/plugins/splash/script/script-execute.h [new file with mode: 0644]
src/plugins/splash/script/script-lib-image.c [new file with mode: 0644]
src/plugins/splash/script/script-lib-image.h [new file with mode: 0644]
src/plugins/splash/script/script-lib-image.script [new file with mode: 0644]
src/plugins/splash/script/script-lib-math.c [new file with mode: 0644]
src/plugins/splash/script/script-lib-math.h [new file with mode: 0644]
src/plugins/splash/script/script-lib-math.script [new file with mode: 0644]
src/plugins/splash/script/script-lib-plymouth.c [new file with mode: 0644]
src/plugins/splash/script/script-lib-plymouth.h [new file with mode: 0644]
src/plugins/splash/script/script-lib-plymouth.script [new file with mode: 0644]
src/plugins/splash/script/script-lib-sprite.c [new file with mode: 0644]
src/plugins/splash/script/script-lib-sprite.h [new file with mode: 0644]
src/plugins/splash/script/script-lib-sprite.script [new file with mode: 0644]
src/plugins/splash/script/script-object.c [new file with mode: 0644]
src/plugins/splash/script/script-object.h [new file with mode: 0644]
src/plugins/splash/script/script-parse.c [new file with mode: 0644]
src/plugins/splash/script/script-parse.h [new file with mode: 0644]
src/plugins/splash/script/script.c [new file with mode: 0644]
src/plugins/splash/script/script.h [new file with mode: 0644]
src/plugins/splash/script/stringify.pl [new file with mode: 0755]
themes/Makefile.am
themes/script/Makefile.am [new file with mode: 0644]
themes/script/script.plymouth.in [new file with mode: 0644]
themes/script/script.script [new file with mode: 0644]

index bcd7d7b024caaba22d4c47dcf6ee08c89ee53aaf..f7353401c4eb3d9090c7fefb4036ef864f20e7f0 100644 (file)
@@ -207,6 +207,7 @@ AC_OUTPUT([Makefile
            src/plugins/splash/details/Makefile
            src/plugins/splash/space-flares/Makefile
            src/plugins/splash/two-step/Makefile
+           src/plugins/splash/script/Makefile
            src/plugins/controls/Makefile
            src/plugins/controls/label/Makefile
            src/Makefile
@@ -222,6 +223,7 @@ AC_OUTPUT([Makefile
            themes/details/Makefile
            themes/solar/Makefile
            themes/glow/Makefile
+           themes/script/Makefile
            images/Makefile
            scripts/Makefile
 ])
index f8316ececaac6daf5b51a312c0804c1f7bff7307..3510531dc64b87870a529bb4302b17ed02c93558 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = throbgress fade-throbber text details space-flares two-step
+SUBDIRS = throbgress fade-throbber text details space-flares two-step script
 MAINTAINERCLEANFILES = Makefile.in
 
 if ADD_DEFAULT_PLUGIN_LINK
diff --git a/src/plugins/splash/script/Makefile.am b/src/plugins/splash/script/Makefile.am
new file mode 100644 (file)
index 0000000..0c02f35
--- /dev/null
@@ -0,0 +1,59 @@
+INCLUDES = -I$(top_srcdir)                                                    \
+           -I$(srcdir)/../../../libply                                        \
+           -I$(srcdir)/../../../libplybootsplash                              \
+           -I$(srcdir)/../../..                                               \
+           -I$(srcdir)/../..                                                  \
+           -I$(srcdir)/..                                                     \
+           -I$(srcdir)
+
+plugindir = $(libdir)/plymouth
+plugin_LTLIBRARIES = script.la
+
+script_la_CFLAGS =  $(PLYMOUTH_CFLAGS)                                        \
+                    -DPLYMOUTH_IMAGE_DIR=\"$(datadir)/plymouth/\"             \
+                    -DPLYMOUTH_LOGO_FILE=\"$(logofile)\"                      \
+                    -DPLYMOUTH_BACKGROUND_COLOR=$(background_color)           \
+                    -DPLYMOUTH_BACKGROUND_END_COLOR=$(background_end_color)   \
+                    -DPLYMOUTH_BACKGROUND_START_COLOR=$(background_start_color)
+script_la_LDFLAGS = -module -avoid-version -export-dynamic
+script_la_LIBADD =  $(PLYMOUTH_LIBS)                                          \
+                    ../../../libply/libply.la                                 \
+                    ../../../libplybootsplash/libplybootsplash.la
+script_la_SOURCES = $(srcdir)/plugin.c                                        \
+                    $(srcdir)/plugin.h                                        \
+                    $(srcdir)/script.c                                        \
+                    $(srcdir)/script.h                                        \
+                    $(srcdir)/script-parse.c                                  \
+                    $(srcdir)/script-parse.h                                  \
+                    $(srcdir)/script-execute.c                                \
+                    $(srcdir)/script-execute.h                                \
+                    $(srcdir)/script-object.c                                 \
+                    $(srcdir)/script-object.h                                 \
+                    $(srcdir)/script-lib-image.c                              \
+                    $(srcdir)/script-lib-image.h                              \
+                    $(srcdir)/script-lib-image.script                         \
+                    $(srcdir)/script-lib-sprite.c                             \
+                    $(srcdir)/script-lib-sprite.h                             \
+                    $(srcdir)/script-lib-sprite.script                        \
+                    $(srcdir)/script-lib-plymouth.c                           \
+                    $(srcdir)/script-lib-plymouth.h                           \
+                    $(srcdir)/script-lib-plymouth.script                      \
+                    $(srcdir)/script-lib-math.c                               \
+                    $(srcdir)/script-lib-math.h                               \
+                    $(srcdir)/script-lib-math.script                          \
+                    $(srcdir)/ply-scan.c                                      \
+                    $(srcdir)/ply-scan.h                                      
+
+MAINTAINERCLEANFILES = Makefile.in
+CLEANFILES = *.script.string
+
+
+EXTRA_DIST = stringify.pl
+
+%.string: %.script stringify.pl
+       ./stringify.pl < $< > $@
+    
+script-lib-image.c : script-lib-image.string
+script-lib-sprite.c : script-lib-sprite.string
+script-lib-math.c : script-lib-math.string
+script-lib-plymouth.c : script-lib-plymouth.string
diff --git a/src/plugins/splash/script/plugin.c b/src/plugins/splash/script/plugin.c
new file mode 100644 (file)
index 0000000..b3f922c
--- /dev/null
@@ -0,0 +1,464 @@
+/* plugin.c - boot script plugin
+ *
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *                     2008 Charlie Brej <cbrej@cs.man.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Charlie Brej <cbrej@cs.man.ac.uk>
+ *             Ray Strode <rstrode@redhat.com>
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <values.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "ply-boot-splash-plugin.h"
+#include "ply-buffer.h"
+#include "ply-entry.h"
+#include "ply-event-loop.h"
+#include "ply-key-file.h"
+#include "ply-label.h"
+#include "ply-list.h"
+#include "ply-logger.h"
+#include "ply-frame-buffer.h"
+#include "ply-image.h"
+#include "ply-trigger.h"
+#include "ply-utils.h"
+#include "ply-window.h"
+
+#include "script.h"
+#include "script-parse.h"
+#include "script-object.h"
+#include "script-execute.h"
+#include "script-lib-image.h"
+#include "script-lib-sprite.h"
+#include "script-lib-plymouth.h"
+#include "script-lib-math.h"
+
+#include <linux/kd.h>
+
+#ifndef FRAMES_PER_SECOND
+#define FRAMES_PER_SECOND 50
+#endif
+
+
+typedef enum {
+  PLY_BOOT_SPLASH_DISPLAY_NORMAL,
+  PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY,
+  PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY
+} ply_boot_splash_display_type_t;
+
+struct _ply_boot_splash_plugin
+{
+  ply_event_loop_t *loop;
+  ply_boot_splash_mode_t mode;
+  ply_frame_buffer_t *frame_buffer;
+  ply_window_t *window;
+  
+  ply_boot_splash_display_type_t state;
+  
+  char *script_filename;
+  char *image_dir;
+  double progress;
+  double progress_target;
+
+  script_state   *script_state;
+  script_op      *script_main_op;
+  script_lib_sprite_data_t *script_sprite_lib;
+  script_lib_image_data_t  *script_image_lib;
+  script_lib_plymouth_data_t  *script_plymouth_lib;
+  script_lib_math_data_t  *script_math_lib;
+
+  uint32_t is_animating : 1;
+};
+
+void destroy_plugin (ply_boot_splash_plugin_t *plugin);
+static void add_handlers (ply_boot_splash_plugin_t *plugin);
+static void remove_handlers (ply_boot_splash_plugin_t *plugin);
+static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin);
+static void stop_animation (ply_boot_splash_plugin_t *plugin);
+ply_boot_splash_plugin_t *create_plugin (ply_key_file_t *key_file);
+
+
+ply_boot_splash_plugin_t *
+create_plugin (ply_key_file_t *key_file)
+{
+  ply_boot_splash_plugin_t *plugin;
+  srand ((int) ply_get_timestamp ());
+  
+  plugin = calloc (1, sizeof (ply_boot_splash_plugin_t));
+
+  plugin->image_dir = ply_key_file_get_value (key_file, "script", "ImageDir");
+  plugin->script_filename = ply_key_file_get_value (key_file, "script", "ScriptFile");
+  plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
+  plugin->progress = 0;
+  plugin->progress_target = -1;
+  return plugin;
+}
+
+void
+destroy_plugin (ply_boot_splash_plugin_t *plugin)
+{
+  if (plugin == NULL)
+    return;
+
+  remove_handlers (plugin);
+
+  if (plugin->loop != NULL)
+    {
+      stop_animation (plugin);
+      ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
+                                             detach_from_event_loop,
+                                             plugin);
+      detach_from_event_loop (plugin);
+    }
+    
+  free (plugin->script_filename);
+  free (plugin->image_dir);
+  free (plugin);
+}
+
+static void
+on_timeout (ply_boot_splash_plugin_t *plugin)
+{
+  double sleep_time;
+  double now;
+
+  now = ply_get_timestamp ();
+
+ if (plugin->script_plymouth_lib->script_refresh_func){
+    script_state* sub_state = script_state_init_sub(plugin->script_state);
+    script_return ret = script_execute(sub_state, plugin->script_plymouth_lib->script_refresh_func->data.function->data.script);    // FIXME too many redirections
+    if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+    script_state_destroy(sub_state);
+    }
+ script_lib_sprite_refresh(plugin->script_sprite_lib);
+  
+  sleep_time = 1.0 / FRAMES_PER_SECOND;
+  ply_event_loop_watch_for_timeout (plugin->loop, 
+                                    sleep_time,
+                                    (ply_event_loop_timeout_handler_t)
+                                    on_timeout, plugin);
+}
+
+static void
+on_boot_progress (ply_boot_splash_plugin_t *plugin,
+                  double                    duration,
+                  double                    percent_done)
+{
+  if (plugin->progress_target<0)
+    plugin->progress = percent_done;
+  plugin->progress_target = percent_done;
+}
+
+
+static bool
+start_animation (ply_boot_splash_plugin_t *plugin)
+{
+  ply_frame_buffer_area_t area;
+  assert (plugin != NULL);
+  assert (plugin->loop != NULL);
+
+  if (plugin->is_animating)
+     return true;
+
+  ply_frame_buffer_get_size (plugin->frame_buffer, &area);
+
+  ply_window_draw_area (plugin->window, area.x, area.y, area.width, area.height);
+  
+ ply_trace ("starting simple");
+ plugin->script_main_op = script_parse_file (plugin->script_filename);
+ ply_trace ("starting simple");
+ plugin->script_state = script_state_new(plugin);
+ plugin->script_image_lib = script_lib_image_setup(plugin->script_state,plugin->image_dir);
+ plugin->script_sprite_lib = script_lib_sprite_setup(plugin->script_state, plugin->window);
+ plugin->script_plymouth_lib = script_lib_plymouth_setup(plugin->script_state);
+ plugin->script_math_lib = script_lib_math_setup(plugin->script_state);
+ script_return ret = script_execute(plugin->script_state, plugin->script_main_op);
+ if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+
+  
+
+  on_timeout (plugin);
+
+  plugin->is_animating = true;
+  return true;
+}
+
+static void
+stop_animation (ply_boot_splash_plugin_t *plugin)
+{
+  assert (plugin != NULL);
+  assert (plugin->loop != NULL);
+
+  if (!plugin->is_animating)
+     return;
+
+  plugin->is_animating = false;
+  if (plugin->loop != NULL)
+    {
+      ply_event_loop_stop_watching_for_timeout (plugin->loop,
+                                                (ply_event_loop_timeout_handler_t)
+                                                on_timeout, plugin);
+    }
+ script_state_destroy(plugin->script_state);
+ script_parse_op_free (plugin->script_main_op);
+ script_lib_sprite_destroy(plugin->script_sprite_lib);
+ script_lib_image_destroy(plugin->script_image_lib);
+ script_lib_plymouth_destroy(plugin->script_plymouth_lib);
+ script_lib_math_destroy(plugin->script_math_lib);
+}
+
+static void
+on_interrupt (ply_boot_splash_plugin_t *plugin)
+{
+  ply_event_loop_exit (plugin->loop, 1);
+  stop_animation (plugin);
+  ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT);
+}
+
+static void
+detach_from_event_loop (ply_boot_splash_plugin_t *plugin)
+{
+  plugin->loop = NULL;
+}
+
+void
+on_keyboard_input (ply_boot_splash_plugin_t *plugin,
+                   const char               *keyboard_input,
+                   size_t                    character_size)
+{
+}
+
+void
+on_backspace (ply_boot_splash_plugin_t *plugin)
+{
+}
+
+void
+on_enter (ply_boot_splash_plugin_t *plugin,
+          const char               *text)
+{
+}
+
+
+void
+on_draw (ply_boot_splash_plugin_t *plugin,
+         int                       x,
+         int                       y,
+         int                       width,
+         int                       height)
+{
+}
+
+void
+on_erase (ply_boot_splash_plugin_t *plugin,
+          int                       x,
+          int                       y,
+          int                       width,
+          int                       height)
+{
+}
+
+static void
+add_handlers (ply_boot_splash_plugin_t *plugin)
+{
+  ply_window_add_keyboard_input_handler (plugin->window,
+                                         (ply_window_keyboard_input_handler_t)
+                                         on_keyboard_input, plugin);
+  ply_window_add_backspace_handler (plugin->window,
+                                    (ply_window_backspace_handler_t)
+                                    on_backspace, plugin);
+  ply_window_add_enter_handler (plugin->window,
+                                (ply_window_enter_handler_t)
+                                on_enter, plugin);
+  ply_window_set_draw_handler (plugin->window,
+                               (ply_window_draw_handler_t)
+                               on_draw, plugin);
+  ply_window_set_erase_handler (plugin->window,
+                               (ply_window_erase_handler_t)
+                               on_erase, plugin);
+}
+
+static void
+remove_handlers (ply_boot_splash_plugin_t *plugin)
+{
+
+  ply_window_remove_keyboard_input_handler (plugin->window, (ply_window_keyboard_input_handler_t) on_keyboard_input);
+  ply_window_remove_backspace_handler (plugin->window, (ply_window_backspace_handler_t) on_backspace);
+  ply_window_remove_enter_handler (plugin->window, (ply_window_enter_handler_t) on_enter);
+  ply_window_set_draw_handler (plugin->window, NULL, NULL);
+  ply_window_set_erase_handler (plugin->window, NULL, NULL);
+}
+
+void
+add_window (ply_boot_splash_plugin_t *plugin,
+            ply_window_t             *window)
+{
+  plugin->window = window;
+}
+
+void
+remove_window (ply_boot_splash_plugin_t *plugin,
+               ply_window_t             *window)
+{
+  plugin->window = NULL;
+}
+
+bool
+show_splash_screen (ply_boot_splash_plugin_t *plugin,
+                    ply_event_loop_t         *loop,
+                    ply_buffer_t             *boot_buffer,
+                    ply_boot_splash_mode_t    mode)
+{
+  assert (plugin != NULL);
+
+  add_handlers (plugin);
+
+  plugin->loop = loop;
+  plugin->mode = mode;
+
+  plugin->frame_buffer = ply_window_get_frame_buffer (plugin->window);
+
+  ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
+                                 detach_from_event_loop,
+                                 plugin);
+
+  ply_event_loop_watch_signal (plugin->loop,
+                               SIGINT,
+                               (ply_event_handler_t) 
+                               on_interrupt, plugin);
+
+  ply_trace ("setting graphics mode");
+  if (!ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_GRAPHICS))
+    return false;
+  ply_window_clear_screen (plugin->window);
+  ply_window_hide_text_cursor (plugin->window);
+
+  ply_trace ("starting boot animation");
+  return start_animation (plugin);
+  
+}
+
+void
+update_status (ply_boot_splash_plugin_t *plugin,
+               const char               *status)
+{
+  assert (plugin != NULL);
+}
+
+void
+hide_splash_screen (ply_boot_splash_plugin_t *plugin,
+                    ply_event_loop_t         *loop)
+{
+  assert (plugin != NULL);
+
+  remove_handlers (plugin);
+
+  if (plugin->loop != NULL)
+    {
+      stop_animation (plugin);
+
+      ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t)
+                                             detach_from_event_loop,
+                                             plugin);
+      detach_from_event_loop (plugin);
+    }
+
+  plugin->frame_buffer = NULL;
+
+  ply_window_set_mode (plugin->window, PLY_WINDOW_MODE_TEXT);
+}
+
+void
+on_root_mounted (ply_boot_splash_plugin_t *plugin)
+{
+}
+
+void
+become_idle (ply_boot_splash_plugin_t *plugin,
+             ply_trigger_t            *idle_trigger)
+{
+  ply_trigger_pull (idle_trigger, NULL);
+}
+
+
+
+void display_normal (ply_boot_splash_plugin_t *plugin)
+{
+  plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
+}
+
+void
+display_password (ply_boot_splash_plugin_t *plugin,
+                  const char               *prompt,
+                  int                       bullets)
+{
+  plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
+}
+
+void
+display_question (ply_boot_splash_plugin_t *plugin,
+                  const char               *prompt,
+                  const char               *entry_text)
+{
+  plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY;
+}
+
+ply_boot_splash_plugin_interface_t *
+ply_boot_splash_plugin_get_interface (void)
+{
+  static ply_boot_splash_plugin_interface_t plugin_interface =
+    {
+      .create_plugin = create_plugin,
+      .destroy_plugin = destroy_plugin,
+      .add_window = add_window,
+      .remove_window = remove_window,
+      .show_splash_screen = show_splash_screen,
+      .update_status = update_status,
+      .on_boot_progress = on_boot_progress,
+      .hide_splash_screen = hide_splash_screen,
+      .on_root_mounted = on_root_mounted,
+      .become_idle = become_idle,
+      .display_normal = display_normal,
+      .display_password = display_password,
+      .display_question = display_question,      
+    };
+
+  return &plugin_interface;
+}
+
+/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
diff --git a/src/plugins/splash/script/plugin.h b/src/plugins/splash/script/plugin.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/plugins/splash/script/ply-scan.c b/src/plugins/splash/script/ply-scan.c
new file mode 100644 (file)
index 0000000..d047387
--- /dev/null
@@ -0,0 +1,240 @@
+#include "ply-bitarray.h"
+#include "ply-scan.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+static ply_scan_t* ply_scan_new(void)
+{
+ unsigned char* chars;
+ ply_scan_t* scan = calloc(1, sizeof(ply_scan_t));
+ scan->tokens = NULL;
+ scan->tokencount = 0;
+ scan->identifier_1st_char = ply_bitarray_new(256);
+ scan->identifier_nth_char = ply_bitarray_new(256);
+ for (chars = (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; *chars; chars++){
+    ply_bitarray_set(scan->identifier_1st_char, *chars);
+    }
+ for (chars = (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"; *chars; chars++){
+    ply_bitarray_set(scan->identifier_nth_char, *chars);
+    }
+ return scan;
+}
+
+ply_scan_t* ply_scan_file(char* filename)
+{
+ int fd = open(filename, O_RDONLY);
+ if (fd<0) return NULL;
+ ply_scan_t* scan = ply_scan_new();
+ scan->source.fd = fd;
+ scan->source_is_file = true;
+ ply_scan_get_next_char(scan);
+ return scan;
+}
+
+ply_scan_t* ply_scan_string(char* string)
+{
+ ply_scan_t* scan = ply_scan_new();
+ scan->source.string = string;
+ scan->source_is_file = false;
+ ply_scan_get_next_char(scan);
+ return scan;
+}
+
+void ply_scan_token_clean(ply_scan_token_t* token)
+{
+ switch (token->type){
+    case PLY_SCAN_TOKEN_TYPE_EMPTY:
+    case PLY_SCAN_TOKEN_TYPE_EOF:
+    case PLY_SCAN_TOKEN_TYPE_INTEGER:
+    case PLY_SCAN_TOKEN_TYPE_SYMBOL:
+        break;
+    case PLY_SCAN_TOKEN_TYPE_IDENTIFIER:
+    case PLY_SCAN_TOKEN_TYPE_STRING:
+        free(token->data.string);
+        break;
+    }
+ token->type = PLY_SCAN_TOKEN_TYPE_EMPTY;
+}
+
+void ply_scan_free(ply_scan_t* scan)
+{
+ int i;
+ if (scan->source_is_file) close(scan->source.fd);
+ for (i=0; i<scan->tokencount; i++){
+    ply_scan_token_clean(scan->tokens[i]);
+    free(scan->tokens[i]);
+    }
+ ply_bitarray_free(scan->identifier_1st_char);
+ ply_bitarray_free(scan->identifier_nth_char);
+ free(scan->tokens);
+ free(scan);
+}
+
+unsigned char ply_scan_get_current_char(ply_scan_t* scan)
+{
+ return scan->cur_char;
+}
+
+unsigned char ply_scan_get_next_char(ply_scan_t* scan)
+{
+ if (scan->source_is_file) {
+    int got = read (scan->source.fd, &scan->cur_char, 1);
+    if (!got) return 0;                                             // FIXME a better way of doing EOF etc
+    }
+ else {
+    scan->cur_char = *scan->source.string;
+    if (scan->cur_char) scan->source.string++;
+    }
+ // update indexes
+ return scan->cur_char;
+}
+
+void ply_scan_read_next_token(ply_scan_t* scan, ply_scan_token_t* token)
+{
+ unsigned char curchar = ply_scan_get_current_char(scan);
+ while(true){
+    if (curchar == ' ')  {curchar = ply_scan_get_next_char(scan); continue;}
+    if (curchar == '\n') {curchar = ply_scan_get_next_char(scan); continue;}
+    if (curchar == '\t') {curchar = ply_scan_get_next_char(scan); continue;}
+    break;
+    }
+ if (ply_bitarray_lookup(scan->identifier_1st_char, curchar)){
+    token->type = PLY_SCAN_TOKEN_TYPE_IDENTIFIER;
+    int index = 0;
+    token->data.string = NULL;
+    do {
+        token->data.string = realloc(token->data.string, (index+2)*sizeof(char));
+        token->data.string[index] = curchar;
+        token->data.string[index+1] = '\0';
+        index++;
+        curchar = ply_scan_get_next_char(scan);
+        }
+    while (ply_bitarray_lookup(scan->identifier_nth_char, curchar));
+    return;
+    }
+ if (curchar >= '0' && curchar <= '9'){
+    token->type = PLY_SCAN_TOKEN_TYPE_INTEGER;
+    long long int value = 0;
+    do {
+        value *= 10;
+        value += curchar - '0';
+        curchar = ply_scan_get_next_char(scan);
+        }
+    while (curchar >= '0' && curchar <= '9');
+    token->data.integer = value;
+    return;
+    }
+ if (!curchar) {
+    token->type = PLY_SCAN_TOKEN_TYPE_EOF;
+    return;
+    }
+ if (curchar == '"') {
+    token->type = PLY_SCAN_TOKEN_TYPE_STRING;
+    int index = 0;
+    token->data.string = malloc(sizeof(char));
+    token->data.string[0] = '\0';
+
+    while (1){
+        curchar = ply_scan_get_next_char(scan);
+        if (curchar == '"') break;
+        assert(curchar != '\0');
+        if (curchar == '\\') {
+            curchar = ply_scan_get_next_char(scan);
+            switch (curchar){
+                case 'n':
+                    curchar = '\n';
+                    break;
+                case '0':
+                    curchar = '\0';
+                    break;
+                case '"':
+                    curchar = '\"';
+                    break;
+                default:
+                    break;
+                }
+            }
+        token->data.string = realloc(token->data.string, (index+2)*sizeof(char));
+        token->data.string[index] = curchar;
+        token->data.string[index+1] = '\0';
+        index++;
+        }
+    ply_scan_get_next_char(scan);
+    return;
+    }
+ // all other
+ token->type = PLY_SCAN_TOKEN_TYPE_SYMBOL;
+ token->data.symbol = curchar;
+ ply_scan_get_next_char(scan);
+ return;
+}
+
+
+static ply_scan_token_t* ply_scan_peek_token(ply_scan_t* scan, int n)
+{
+ int i;
+ if (scan->tokencount <= n){
+    scan->tokens = realloc(scan->tokens, (n+1)*sizeof(ply_scan_token_t*));
+    for (i = scan->tokencount; i<=n; i++){                                      // FIXME warning about possibely inifnite loop
+        scan->tokens[i] = malloc(sizeof(ply_scan_token_t));
+        scan->tokens[i]->type = PLY_SCAN_TOKEN_TYPE_EMPTY;
+        }
+    scan->tokencount = n+1;
+    }
+ if (scan->tokens[n]->type == PLY_SCAN_TOKEN_TYPE_EMPTY){
+    if (n > 0 && scan->tokens[n-1]->type == PLY_SCAN_TOKEN_TYPE_EMPTY)
+        ply_scan_peek_token(scan, n-1);
+    ply_scan_read_next_token(scan, scan->tokens[n]);
+//     printf("%d:", n);
+//     switch (scan->tokens[n]->type){
+//         case PLY_SCAN_TOKEN_TYPE_STRING:
+//             printf("\"%s\"\n", scan->tokens[n]->data.string);
+//             break;
+//         case PLY_SCAN_TOKEN_TYPE_IDENTIFIER:
+//             printf("%s\n", scan->tokens[n]->data.string);
+//             break;
+//         case PLY_SCAN_TOKEN_TYPE_SYMBOL:
+//             printf("'%c'\n", scan->tokens[n]->data.symbol);
+//             break;
+//         case PLY_SCAN_TOKEN_TYPE_INTEGER:
+//             printf("%d\n", (int)scan->tokens[n]->data.integer);
+//             break;
+//         }
+    } 
+ return scan->tokens[n];
+}
+
+ply_scan_token_t* ply_scan_get_next_token(ply_scan_t* scan)
+{
+ int i;
+ ply_scan_token_clean(scan->tokens[0]);
+ for (i=0; i<(scan->tokencount-1); i++){
+    *scan->tokens[i] = *scan->tokens[i+1];
+    }
+ scan->tokens[(scan->tokencount-1)]->type = PLY_SCAN_TOKEN_TYPE_EMPTY;
+ return ply_scan_peek_token(scan, 0);
+}
+
+ply_scan_token_t* ply_scan_get_current_token(ply_scan_t* scan)
+{
+ return ply_scan_peek_token(scan, 0);
+}
+
+ply_scan_token_t* ply_scan_peek_next_token(ply_scan_t* scan)
+{
+ return ply_scan_peek_token(scan, 1);
+}
+
+
diff --git a/src/plugins/splash/script/ply-scan.h b/src/plugins/splash/script/ply-scan.h
new file mode 100644 (file)
index 0000000..d7cf5a6
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef PLY_SCAN_H
+#define PLY_SCAN_H
+
+#include "ply-bitarray.h"
+#include <stdbool.h>
+
+typedef enum
+{
+ PLY_SCAN_TOKEN_TYPE_EMPTY,
+ PLY_SCAN_TOKEN_TYPE_EOF,
+ PLY_SCAN_TOKEN_TYPE_INTEGER,
+ PLY_SCAN_TOKEN_TYPE_IDENTIFIER,
+ PLY_SCAN_TOKEN_TYPE_STRING,
+ PLY_SCAN_TOKEN_TYPE_SYMBOL,
+} ply_scan_token_type_t;
+
+typedef struct
+{
+ ply_scan_token_type_t type;
+ union
+ {
+    char* string;
+    char symbol;
+    long long int integer;
+ } data;
+} ply_scan_token_t;
+
+typedef struct
+{
+ union
+ {
+  int fd;
+  char* string;
+ } source;
+  unsigned char cur_char;
+  ply_bitarray_t *identifier_1st_char;
+  ply_bitarray_t *identifier_nth_char;
+  int tokencount;
+  ply_scan_token_t **tokens;
+  bool source_is_file;
+} ply_scan_t;
+
+ply_scan_t* ply_scan_file(char* filename);
+ply_scan_t* ply_scan_string(char* string);
+void ply_scan_token_clean(ply_scan_token_t* token);
+void ply_scan_free(ply_scan_t* scan);
+unsigned char ply_scan_get_current_char(ply_scan_t* scan);
+unsigned char ply_scan_get_next_char(ply_scan_t* scan);
+ply_scan_token_t* ply_scan_get_current_token(ply_scan_t* scan);
+ply_scan_token_t* ply_scan_get_next_token(ply_scan_t* scan);
+ply_scan_token_t* ply_scan_peek_next_token(ply_scan_t* scan);
+void ply_scan_read_next_token(ply_scan_t* scan, ply_scan_token_t* token);
+
+#endif /* PLY_SCAN_H */
diff --git a/src/plugins/splash/script/script-execute.c b/src/plugins/splash/script/script-execute.c
new file mode 100644 (file)
index 0000000..63bd634
--- /dev/null
@@ -0,0 +1,720 @@
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+
+
+static script_obj* script_evaluate (script_state* state, script_exp* exp);
+
+static script_obj* script_evaluate_plus (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* obj = NULL;
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                obj = script_obj_new_int (script_obj_a->data.integer + script_obj_b->data.integer);
+                break;
+            case SCRIPT_OBJ_TYPE_NULL:
+                obj = script_obj_new_int (script_obj_a->data.integer);                // int + NULL = int  ? meh
+                break;
+            default:
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_NULL:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                obj = script_obj_new_int (script_obj_b->data.integer);
+                break;
+            case SCRIPT_OBJ_TYPE_STRING:
+                {
+                obj = script_obj_new_string (script_obj_b->data.string);
+                break;
+                }
+            default:
+                break;
+            }
+        break;
+        }
+    
+    case SCRIPT_OBJ_TYPE_STRING:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                {
+                char* newstring;
+                asprintf(&newstring, "%s%d", script_obj_a->data.string, script_obj_b->data.integer);
+                obj = script_obj_new_string (newstring);                    // FIXME these two asprintfs complain about ignored returned values
+                free(newstring);
+                break;
+                }
+            case SCRIPT_OBJ_TYPE_STRING:
+                {
+                char* newstring;
+                asprintf(&newstring, "%s%s", script_obj_a->data.string, script_obj_b->data.string);
+                obj = script_obj_new_string (newstring);
+                free(newstring);
+                break;
+            case SCRIPT_OBJ_TYPE_NULL:
+                obj = script_obj_new_string (script_obj_a->data.string);
+                break;
+                }
+            default:
+                break;
+            }
+        break;
+        }
+       
+    default:
+        break;
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+static script_obj* script_evaluate_minus (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* obj = NULL;
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                obj = script_obj_new_int (script_obj_a->data.integer - script_obj_b->data.integer);
+                break;
+            case SCRIPT_OBJ_TYPE_NULL:
+                obj = script_obj_new_int (script_obj_a->data.integer);
+                break;
+            default:
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_NULL:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                obj = script_obj_new_int (-script_obj_b->data.integer);
+                break;
+            default:
+                break;
+            }
+        break;
+        }        
+    default:
+        break;
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+static script_obj* script_evaluate_mul (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* obj = NULL;
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                obj = script_obj_new_int (script_obj_a->data.integer * script_obj_b->data.integer);
+                break;
+            default:
+                break;
+            }
+        break;
+        }
+    default:
+        break;
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+static script_obj* script_evaluate_div (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* obj = NULL;
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                if (script_obj_b->data.integer == 0) obj = script_obj_new_null ();
+                else obj = script_obj_new_int (script_obj_a->data.integer / script_obj_b->data.integer);
+                break;
+            default:
+                break;
+            }
+        break;
+        }
+    default:
+        break;
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+
+static script_obj* script_evaluate_mod (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* obj = NULL;
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_INT:
+                if (script_obj_b->data.integer == 0) obj = script_obj_new_null ();
+                else obj = script_obj_new_int (script_obj_a->data.integer % script_obj_b->data.integer);
+                break;
+            default:
+                break;
+            }
+        break;
+        }
+    default:
+        break;
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+static script_obj* script_evaluate_hash (script_state* state, script_exp* exp)
+{
+ script_obj* hash = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* key  = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj* hash_dereffed = script_obj_deref_direct(hash);
+ script_obj* obj;
+ script_obj_deref (&key);
+ if (hash_dereffed->type == SCRIPT_OBJ_TYPE_HASH){
+    script_obj_deref (&hash);
+    }
+ else {
+    script_obj_reset (hash);
+    script_obj* newhash  = script_obj_new_hash ();
+    hash->type = SCRIPT_OBJ_TYPE_REF;
+    hash->data.obj = newhash;
+    script_obj_deref (&hash);
+    }
+ char* name = script_obj_as_string(key);
+ script_vareable* vareable = ply_hashtable_lookup (hash->data.hash, name);
+ if (vareable) {
+    obj = vareable->object;
+    free(name);
+    }
+ else {
+    obj = script_obj_new_null ();
+    vareable = malloc(sizeof(script_vareable));
+    vareable->name = name;
+    vareable->object = obj;
+    ply_hashtable_insert (hash->data.hash, vareable->name, vareable);
+    }
+ script_obj_ref (obj);
+ script_obj_unref (hash);
+ script_obj_unref (key);
+ return obj;
+}
+
+
+static script_obj* script_evaluate_var (script_state* state, script_exp* exp)
+{
+ char* name = exp->data.string;
+ script_obj* obj;
+ assert (state->global->type == SCRIPT_OBJ_TYPE_HASH);
+ assert (state->local->type == SCRIPT_OBJ_TYPE_HASH);
+ script_vareable* vareable = ply_hashtable_lookup (state->local->data.hash, name);
+ if (!vareable)
+    vareable = ply_hashtable_lookup (state->global->data.hash, name);
+ if (vareable) {
+    obj = vareable->object;
+    script_obj_ref (obj);
+    return obj;
+    }
+ obj = script_obj_new_null ();
+
+ vareable = malloc(sizeof(script_vareable));
+ vareable->name = strdup(name);
+ vareable->object = obj;
+
+ ply_hashtable_insert (state->local->data.hash, vareable->name, vareable);
+ script_obj_ref (obj);
+ return obj;
+}
+
+
+static script_obj* script_evaluate_assign (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj_deref (&script_obj_b);
+ script_obj_reset (script_obj_a);
+ script_obj_assign (script_obj_a, script_obj_b);
+ script_obj_unref(script_obj_b);
+ return script_obj_a;
+}
+
+static script_obj* script_evaluate_cmp (script_state* state, script_exp* exp)
+{
+ script_obj* script_obj_a = script_evaluate (state, exp->data.dual.sub_a);
+ script_obj* script_obj_b = script_evaluate (state, exp->data.dual.sub_b);
+ script_obj_deref (&script_obj_a);
+ script_obj_deref (&script_obj_b);
+ int gt=0;
+ int lt=0;
+ int eq=0;
+ int ne=0;
+ int val;
+ int valset=0;
+  switch (script_obj_a->type){
+    case SCRIPT_OBJ_TYPE_REF:
+        assert(0);
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_INT:
+                val = script_obj_a->data.integer - script_obj_b->data.integer;
+                valset=1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_STRING:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_STRING:
+                val = strcmp(script_obj_a->data.string, script_obj_b->data.string);
+                valset=1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_HASH:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_HASH:
+                if (script_obj_a == script_obj_b) eq = 1;
+                else ne = 1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_FUNCTION:
+                if (script_obj_a == script_obj_b) eq = 1;
+                else ne = 1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_NULL:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_NULL:
+                eq = 1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        {
+        switch (script_obj_b->type){
+            case SCRIPT_OBJ_TYPE_REF:
+                assert(0);
+            case SCRIPT_OBJ_TYPE_NATIVE:
+                eq = 1;
+                break;
+            default:
+                ne = 1;
+                break;
+            }
+        break;
+        }
+    }
+ if(valset){
+    if (val < 0) {lt = 1; ne = 1;}
+    if (val == 0) eq = 1;
+    if (val > 0) {gt = 1; ne = 1;}
+    }
+ int reply = 0;
+ switch (exp->type){
+    case SCRIPT_EXP_TYPE_EQ:
+        if (eq) reply=1;
+        break;
+    case SCRIPT_EXP_TYPE_NE:
+        if (ne) reply=1;
+        break;
+    case SCRIPT_EXP_TYPE_GT:
+        if (gt) reply=1;
+        break;
+    case SCRIPT_EXP_TYPE_GE:
+        if (gt || eq) reply=1;
+        break;
+    case SCRIPT_EXP_TYPE_LT:
+        if (lt) reply=1;
+        break;
+    case SCRIPT_EXP_TYPE_LE:
+        if (lt || eq) reply=1;      // CHECKME Errr so "(NULL <= NULL) is true" makes sense?
+        break;
+    default:
+        assert(0);
+    }
+ script_obj_unref (script_obj_a);
+ script_obj_unref (script_obj_b);
+ return script_obj_new_int (reply);
+}
+
+static script_obj* script_evaluate_func (script_state* state, script_exp* exp)
+{
+ script_state localstate;
+ script_obj* func = script_evaluate (state, exp->data.function.name);
+ script_obj* obj = NULL;
+ script_obj_deref (&func);
+ if (func->type != SCRIPT_OBJ_TYPE_FUNCTION)
+    return script_obj_new_null ();
+ localstate = *state;
+ localstate.local = script_obj_new_hash();
+ ply_list_t* parameter_names = func->data.function->parameters;
+ ply_list_t* parameter_data = exp->data.function.parameters;
+ ply_list_node_t *node_name = ply_list_get_first_node (parameter_names);
+ ply_list_node_t *node_data = ply_list_get_first_node (parameter_data);
+ while (node_name && node_data){
+    script_exp* data_exp = ply_list_node_get_data (node_data);
+    char* name = ply_list_node_get_data (node_name);
+    script_obj* data_obj = script_evaluate (state, data_exp);
+    
+    script_vareable* vareable = malloc(sizeof(script_vareable));
+    vareable->name = strdup(name);
+    vareable->object = data_obj;
+
+    ply_hashtable_insert (localstate.local->data.hash, vareable->name, vareable);
+
+    
+    node_name = ply_list_get_next_node (parameter_names, node_name);
+    node_data = ply_list_get_next_node (parameter_data, node_data);
+    }
+ script_return reply;
+ switch (func->data.function->type){
+    case SCRIPT_FUNCTION_TYPE_SCRIPT:
+        {
+        script_op* op = func->data.function->data.script;
+        reply = script_execute (&localstate, op);
+        break;
+        }
+    case SCRIPT_FUNCTION_TYPE_NATIVE:
+        {
+        reply = func->data.function->data.native (&localstate, func->data.function->user_data);
+        break;
+        }
+    }
+ script_obj_unref (localstate.local);
+ script_obj_unref (func);
+ if (reply.type == SCRIPT_RETURN_TYPE_RETURN)
+    obj = reply.object;
+ if (!obj){
+    obj = script_obj_new_null ();
+    }
+ return obj;
+}
+
+
+static script_obj* script_evaluate (script_state* state, script_exp* exp)
+{
+ switch (exp->type){
+    case SCRIPT_EXP_TYPE_PLUS:
+        {
+        return script_evaluate_plus (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_MINUS:
+        {
+        return script_evaluate_minus (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_MUL:
+        {
+        return script_evaluate_mul (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_DIV:
+        {
+        return script_evaluate_div (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_MOD:
+        {
+        return script_evaluate_mod (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_EQ:
+    case SCRIPT_EXP_TYPE_NE:
+    case SCRIPT_EXP_TYPE_GT:
+    case SCRIPT_EXP_TYPE_GE:
+    case SCRIPT_EXP_TYPE_LT:
+    case SCRIPT_EXP_TYPE_LE:
+        {
+        return script_evaluate_cmp (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_TERM_INT:
+        {
+        return script_obj_new_int (exp->data.integer);
+        }
+    case SCRIPT_EXP_TYPE_TERM_STRING:
+        {
+        return script_obj_new_string (exp->data.string);
+        }
+    case SCRIPT_EXP_TYPE_TERM_NULL:
+        {
+        return script_obj_new_null();
+        }
+    case SCRIPT_EXP_TYPE_TERM_LOCAL:
+        {
+        script_obj_ref(state->local);
+        return state->local;
+        }
+    case SCRIPT_EXP_TYPE_TERM_GLOBAL:
+        {
+        script_obj_ref(state->global);
+        return state->global;
+        }
+    case SCRIPT_EXP_TYPE_TERM_VAR:
+        {
+        return script_evaluate_var (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_ASSIGN:
+        {
+        return script_evaluate_assign (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_HASH:
+        {
+        return script_evaluate_hash (state, exp);
+        }
+    case SCRIPT_EXP_TYPE_FUNCTION:
+        {
+        return script_evaluate_func (state, exp);
+        }
+//    default:
+//        printf("unhandeled operation type %d\n", exp->type);
+//        assert(0);
+    }
+ assert(0);
+}
+
+static script_return script_execute_list (script_state* state, ply_list_t* op_list)     // FIXME script_execute returns the return obj
+{
+ script_return reply = {SCRIPT_RETURN_TYPE_NORMAL, NULL};
+ ply_list_node_t *node = ply_list_get_first_node (op_list);
+ for (node = ply_list_get_first_node (op_list); node; node = ply_list_get_next_node (op_list, node)){
+    script_op* op = ply_list_node_get_data (node);
+    reply = script_execute(state, op);
+    switch (reply.type) {
+        case SCRIPT_RETURN_TYPE_NORMAL:
+            break;
+        case SCRIPT_RETURN_TYPE_RETURN:
+        case SCRIPT_RETURN_TYPE_BREAK:
+        case SCRIPT_RETURN_TYPE_CONTINUE:
+            return reply;
+        }
+    }
+ return reply;
+}
+
+
+script_return script_execute (script_state* state, script_op* op)
+{
+ script_return reply = {SCRIPT_RETURN_TYPE_NORMAL, NULL};
+ switch (op->type){
+    case SCRIPT_OP_TYPE_EXPRESSION:
+        {
+        script_obj* obj = script_evaluate (state, op->data.exp);
+        script_obj_unref(obj);     // there is always a reply from all expressions (even assigns) which we chuck away
+        break;
+        }
+    case SCRIPT_OP_TYPE_OP_BLOCK:
+        {
+        reply = script_execute_list (state, op->data.list);
+                // FIXME blocks should normall reply a NULL , but if they replied something else then that was a return
+        break;
+        }
+    case SCRIPT_OP_TYPE_IF:
+        {
+        script_obj* obj = script_evaluate (state, op->data.cond_op.cond);
+        if (script_obj_as_bool(obj)){
+            reply = script_execute (state, op->data.cond_op.op);       // FIXME propagate break
+            }
+        script_obj_unref(obj);
+        break;
+        }
+    case SCRIPT_OP_TYPE_WHILE:
+        {
+        script_obj* obj;
+        while (1){
+            obj = script_evaluate (state, op->data.cond_op.cond);
+            if (script_obj_as_bool(obj)){
+                reply = script_execute (state, op->data.cond_op.op);       // FIXME handle break
+                script_obj_unref(obj);
+                switch (reply.type) {
+                    case SCRIPT_RETURN_TYPE_NORMAL:
+                        break;
+                    case SCRIPT_RETURN_TYPE_RETURN:
+                        return reply;
+                    case SCRIPT_RETURN_TYPE_BREAK:
+                        return (script_return){SCRIPT_RETURN_TYPE_NORMAL, NULL};
+                    case SCRIPT_RETURN_TYPE_CONTINUE:
+                        reply = (script_return){SCRIPT_RETURN_TYPE_NORMAL, NULL};
+                        break;
+                    }
+                }
+            else {
+                script_obj_unref(obj);
+                break;
+                }
+            }
+        break;
+        }
+    case SCRIPT_OP_TYPE_FUNCTION_DEF:
+        {
+        script_obj* obj = script_evaluate(state, op->data.function_def.name);
+        script_obj_reset (obj);
+        obj->type = SCRIPT_OBJ_TYPE_FUNCTION;
+        obj->data.function = op->data.function_def.function;
+        script_obj_unref(obj);
+        break;
+        }
+    case SCRIPT_OP_TYPE_RETURN:
+        {
+        script_obj* obj;
+        if (op->data.exp) obj = script_evaluate (state, op->data.exp);
+        else obj = script_obj_new_null();
+        reply = (script_return){SCRIPT_RETURN_TYPE_RETURN, obj};
+        break;
+        }
+    case SCRIPT_OP_TYPE_BREAK:
+        {
+        reply = (script_return){SCRIPT_RETURN_TYPE_BREAK, NULL};
+        break;
+        }
+    case SCRIPT_OP_TYPE_CONTINUE:
+        {
+        reply = (script_return){SCRIPT_RETURN_TYPE_CONTINUE, NULL};
+        break;
+        }
+    }
+ return reply;
+}
+
+
diff --git a/src/plugins/splash/script/script-execute.h b/src/plugins/splash/script/script-execute.h
new file mode 100644 (file)
index 0000000..ded3f54
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef SCRIPT_EXECUTE_H
+#define SCRIPT_EXECUTE_H
+
+#include "script.h"
+
+script_return script_execute (script_state* state, script_op* op);
+
+
+#endif /* SCRIPT_EXECUTE_H */
diff --git a/src/plugins/splash/script/script-lib-image.c b/src/plugins/splash/script/script-lib-image.c
new file mode 100644 (file)
index 0000000..14df723
--- /dev/null
@@ -0,0 +1,114 @@
+#define _GNU_SOURCE
+#include "ply-image.h"
+#include "ply-utils.h"
+#include "script.h"
+#include "script-object.h"
+#include "script-execute.h"
+#include "script-lib-image.h" 
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#define STRINGIFY_VAR script_lib_image_string
+
+#include "script-lib-image.string"
+
+
+static void image_free (script_obj* obj)
+{
+ ply_image_t *image = obj->data.native.object_data;
+ ply_image_free (image);
+}
+
+
+static script_return image_new (script_state* state, void* user_data)
+{
+ script_lib_image_data_t* data = user_data;
+ script_obj* reply;
+ char* filename;
+ char* path_filename;
+ script_obj* script_obj_filename = script_obj_hash_get_element (state->local, "filename");
+ filename = script_obj_as_string(script_obj_filename);
+ asprintf(&path_filename, "%s/%s", data->image_dir, filename);
+ script_obj_unref(script_obj_filename);
+ ply_image_t *image = ply_image_new (path_filename);
+ if (ply_image_load (image)){
+    reply = script_obj_new_native (image, data->class);
+    }
+ else {
+    reply = script_obj_new_null ();
+    }
+ free(filename);
+ free(path_filename);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply};
+}
+
+static script_return image_get_width (script_state* state, void* user_data)
+{
+ script_lib_image_data_t* data = user_data;
+ script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image");
+ script_obj_deref(&script_obj_image);
+ script_obj* reply;
+ if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_image->data.native.class == data->class){
+    ply_image_t *image = script_obj_image->data.native.object_data;
+    reply = script_obj_new_int (ply_image_get_width (image));
+    }
+ else
+    reply = script_obj_new_null ();
+ script_obj_unref(script_obj_image);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply};
+}
+
+static script_return image_get_height (script_state* state, void* user_data)
+{
+ script_lib_image_data_t* data = user_data;
+ script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image");
+ script_obj_deref(&script_obj_image);
+ script_obj* reply;
+ if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_image->data.native.class == data->class){
+    ply_image_t *image = script_obj_image->data.native.object_data;
+    reply = script_obj_new_int (ply_image_get_height (image));
+    }
+ else
+    reply = script_obj_new_null ();
+ script_obj_unref(script_obj_image);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply};
+}
+
+
+
+
+script_lib_image_data_t* script_lib_image_setup(script_state *state, char* image_dir)
+{
+ script_lib_image_data_t* data = malloc(sizeof(script_lib_image_data_t));
+ data->class = script_obj_native_class_new(image_free, "image", data);
+ data->image_dir = strdup(image_dir);
+
+ script_add_native_function (state->global, "ImageNew", image_new, data, "filename", NULL);
+ script_add_native_function (state->global, "ImageGetWidth", image_get_width, data, "image", NULL);
+ script_add_native_function (state->global, "ImageGetHeight", image_get_height, data, "image", NULL);
+ data->script_main_op = script_parse_string (script_lib_image_string);
+ script_return ret = script_execute(state, data->script_main_op);
+ if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+ return data;
+}
+
+
+void script_lib_image_destroy(script_lib_image_data_t* data)
+{
+ script_obj_native_class_destroy(data->class);
+ free(data->image_dir);
+ script_parse_op_free (data->script_main_op);
+ free(data);
+}
+
diff --git a/src/plugins/splash/script/script-lib-image.h b/src/plugins/splash/script/script-lib-image.h
new file mode 100644 (file)
index 0000000..245718d
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SCRIPT_LIB_IMAGE
+#define SCRIPT_LIB_IMAGE
+
+#include "script.h"
+
+typedef struct
+{
+  script_obj_native_class* class;
+  script_op      *script_main_op;
+  char* image_dir;
+} script_lib_image_data_t;
+
+
+script_lib_image_data_t* script_lib_image_setup(script_state *state, char* image_dir);
+void script_lib_image_destroy(script_lib_image_data_t* data);
+
+#endif /* SCRIPT_LIB_IMAGE */
diff --git a/src/plugins/splash/script/script-lib-image.script b/src/plugins/splash/script/script-lib-image.script
new file mode 100644 (file)
index 0000000..bac9c71
--- /dev/null
@@ -0,0 +1 @@
+   
diff --git a/src/plugins/splash/script/script-lib-math.c b/src/plugins/splash/script/script-lib-math.c
new file mode 100644 (file)
index 0000000..93c3135
--- /dev/null
@@ -0,0 +1,38 @@
+#define _GNU_SOURCE
+#include "ply-utils.h"
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+#include "script-lib-math.h" 
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#define STRINGIFY_VAR script_lib_math_string
+
+#include "script-lib-math.string"
+
+
+
+script_lib_math_data_t* script_lib_math_setup(script_state *state)
+{
+ script_lib_math_data_t* data = malloc(sizeof(script_lib_math_data_t));
+ data->script_main_op = script_parse_string (script_lib_math_string);
+ script_return ret = script_execute(state, data->script_main_op);
+ if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+
+ return data;
+}
+
+
+void script_lib_math_destroy(script_lib_math_data_t* data)
+{
+ script_parse_op_free (data->script_main_op);
+ free(data);
+}
+
diff --git a/src/plugins/splash/script/script-lib-math.h b/src/plugins/splash/script/script-lib-math.h
new file mode 100644 (file)
index 0000000..17e2ebb
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SCRIPT_LIB_MATH
+#define SCRIPT_LIB_MATH
+
+#include "script.h"
+
+typedef struct
+{
+  script_op      *script_main_op;
+} script_lib_math_data_t;
+
+
+script_lib_math_data_t* script_lib_math_setup(script_state *state);
+void script_lib_math_destroy(script_lib_math_data_t* data);
+
+#endif /* SCRIPT_LIB_MATH */
diff --git a/src/plugins/splash/script/script-lib-math.script b/src/plugins/splash/script/script-lib-math.script
new file mode 100644 (file)
index 0000000..bac9c71
--- /dev/null
@@ -0,0 +1 @@
+   
diff --git a/src/plugins/splash/script/script-lib-plymouth.c b/src/plugins/splash/script/script-lib-plymouth.c
new file mode 100644 (file)
index 0000000..0b82e5b
--- /dev/null
@@ -0,0 +1,51 @@
+#define _GNU_SOURCE
+#include "ply-utils.h"
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+#include "script-lib-plymouth.h" 
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#define STRINGIFY_VAR script_lib_plymouth_string
+
+#include "script-lib-plymouth.string"
+
+
+static script_return plymouth_set_refresh (script_state* state, void* user_data)
+{
+ script_lib_plymouth_data_t* data = user_data;
+ script_obj* obj = script_obj_hash_get_element (state->local, "function");
+ script_obj_deref(&obj);
+ if (obj->type == SCRIPT_OBJ_TYPE_FUNCTION){
+    data->script_refresh_func = obj;
+    }
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()};
+}
+
+
+script_lib_plymouth_data_t* script_lib_plymouth_setup(script_state *state)
+{
+ script_lib_plymouth_data_t* data = malloc(sizeof(script_lib_plymouth_data_t));
+ data->script_refresh_func = NULL;
+ script_add_native_function (state->global, "PlymouthSetRefreshFunction", plymouth_set_refresh, data, "function", NULL);
+ data->script_main_op = script_parse_string (script_lib_plymouth_string);
+ script_return ret = script_execute(state, data->script_main_op);
+ if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+
+ return data;
+}
+
+
+void script_lib_plymouth_destroy(script_lib_plymouth_data_t* data)
+{
+ script_parse_op_free (data->script_main_op);
+ script_obj_unref(data->script_refresh_func);
+ free(data);
+}
diff --git a/src/plugins/splash/script/script-lib-plymouth.h b/src/plugins/splash/script/script-lib-plymouth.h
new file mode 100644 (file)
index 0000000..34c38d0
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SCRIPT_LIB_PLYMOUTH
+#define SCRIPT_LIB_PLYMOUTH
+
+#include "script.h"
+
+typedef struct
+{
+  script_op      *script_main_op;
+  script_obj     *script_refresh_func;
+} script_lib_plymouth_data_t;
+
+
+script_lib_plymouth_data_t* script_lib_plymouth_setup(script_state *state);
+void script_lib_plymouth_destroy(script_lib_plymouth_data_t* data);
+
+#endif /* SCRIPT_LIB_PLYMOUTH */
diff --git a/src/plugins/splash/script/script-lib-plymouth.script b/src/plugins/splash/script/script-lib-plymouth.script
new file mode 100644 (file)
index 0000000..bac9c71
--- /dev/null
@@ -0,0 +1 @@
+   
diff --git a/src/plugins/splash/script/script-lib-sprite.c b/src/plugins/splash/script/script-lib-sprite.c
new file mode 100644 (file)
index 0000000..f7982c2
--- /dev/null
@@ -0,0 +1,238 @@
+#include "ply-image.h"
+#include "ply-utils.h"
+#include "ply-window.h"
+#include "ply-logger.h"
+#include "ply-key-file.h"
+#include "script.h"
+#include "script-execute.h"
+#include "script-object.h"
+#include "script-lib-image.h"
+#include "script-lib-sprite.h"
+#include <assert.h>
+#include <stdlib.h>
+
+
+#define STRINGIFY_VAR script_lib_sprite_string
+#include "script-lib-sprite.string"
+
+static void sprite_free (script_obj* obj)
+{
+ script_lib_sprite_data_t* data = obj->data.native.class->user_data;
+ ply_list_remove_data (data->sprite_list, obj->data.native.object_data);
+ sprite_t *sprite = obj->data.native.object_data;
+ if (sprite->image_obj) script_obj_unref(sprite->image_obj);
+ free(obj->data.native.object_data);
+}
+
+static script_return sprite_new (script_state* state, void* user_data)
+{
+ script_lib_sprite_data_t* data = user_data;
+ script_obj* reply;
+ sprite_t *sprite = calloc(1, sizeof(sprite_t));
+ sprite->x = 0;
+ sprite->y = 0;
+ sprite->z = 0;
+ sprite->opacity = 1.0;
+ sprite->old_x = 0;
+ sprite->old_y = 0;
+ sprite->old_z = 0;
+ sprite->old_opacity = 1.0;
+ sprite->refresh_me = false;
+ sprite->image = NULL;
+ sprite->image_obj = NULL;
+ ply_list_append_data (data->sprite_list, sprite);
+ reply = script_obj_new_native (sprite, data->class);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, reply};
+}
+
+
+static script_return sprite_set_image (script_state* state, void* user_data)
+{
+ script_lib_sprite_data_t* data = user_data;
+ script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite");
+ script_obj_deref(&script_obj_sprite);
+ script_obj* script_obj_image = script_obj_hash_get_element (state->local, "image");
+ script_obj_deref(&script_obj_image);
+ if (script_obj_image->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_sprite->data.native.class == data->class){
+    sprite_t *sprite = script_obj_sprite->data.native.object_data;
+    ply_image_t *image = script_obj_image->data.native.object_data;
+    if (sprite->image_obj) script_obj_unref(sprite->image_obj);
+    script_obj_ref(script_obj_image);
+    sprite->image = image;
+    sprite->image_obj = script_obj_image;
+    }
+ script_obj_unref(script_obj_sprite);
+ script_obj_unref(script_obj_image);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()};
+}
+
+
+
+static script_return sprite_set_x (script_state* state, void* user_data)
+{
+ script_lib_sprite_data_t* data = user_data;
+ script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite");
+ script_obj_deref(&script_obj_sprite);
+ script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value");
+ script_obj_deref(&script_obj_value);
+ if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_sprite->data.native.class == data->class){
+    sprite_t *sprite = script_obj_sprite->data.native.object_data;
+    sprite->x = script_obj_as_int(script_obj_value);
+    }
+ script_obj_unref(script_obj_sprite);
+ script_obj_unref(script_obj_value);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()};
+}
+
+static script_return sprite_set_y (script_state* state, void* user_data)
+{
+ script_lib_sprite_data_t* data = user_data;
+ script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite");
+ script_obj_deref(&script_obj_sprite);
+ script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value");
+ script_obj_deref(&script_obj_value);
+ if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_sprite->data.native.class == data->class){
+    sprite_t *sprite = script_obj_sprite->data.native.object_data;
+    sprite->y = script_obj_as_int(script_obj_value);
+    }
+ script_obj_unref(script_obj_sprite);
+ script_obj_unref(script_obj_value);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()};
+}
+
+static script_return sprite_set_z (script_state* state, void* user_data)
+{
+ script_lib_sprite_data_t* data = user_data;
+ script_obj* script_obj_sprite = script_obj_hash_get_element (state->local, "sprite");
+ script_obj_deref(&script_obj_sprite);
+ script_obj* script_obj_value = script_obj_hash_get_element (state->local, "value");
+ script_obj_deref(&script_obj_value);
+ if (script_obj_sprite->type == SCRIPT_OBJ_TYPE_NATIVE &&
+     script_obj_sprite->data.native.class == data->class){
+    sprite_t *sprite = script_obj_sprite->data.native.object_data;
+    sprite->z = script_obj_as_int(script_obj_value);
+    }
+ script_obj_unref(script_obj_sprite);
+ script_obj_unref(script_obj_value);
+ return (script_return){SCRIPT_RETURN_TYPE_RETURN, script_obj_new_null ()};
+}
+
+
+
+
+static void
+draw_area (script_lib_sprite_data_t*            data,
+           int                       x,
+           int                       y,
+           int                       width,
+           int                       height)
+{
+  ply_frame_buffer_area_t clip_area;
+  clip_area.x = x;
+  clip_area.y = y;
+  clip_area.width = width;
+  clip_area.height = height;
+  ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window);
+  
+  ply_frame_buffer_pause_updates (frame_buffer);
+  
+  
+  ply_frame_buffer_fill_with_hex_color (frame_buffer, &clip_area, 0x00000000);
+
+  ply_list_node_t *node;
+  for (node = ply_list_get_first_node (data->sprite_list); node; node = ply_list_get_next_node (data->sprite_list, node))
+    {
+      sprite_t* sprite = ply_list_node_get_data (node);
+      ply_frame_buffer_area_t sprite_area;
+
+
+      sprite_area.x = sprite->x;
+      sprite_area.y = sprite->y;
+
+      if (sprite_area.x>=(x+width)) continue;
+      if (sprite_area.y>=(y+height)) continue;
+
+      sprite_area.width =  ply_image_get_width (sprite->image);
+      sprite_area.height = ply_image_get_height (sprite->image);
+
+      if ((sprite_area.x+(int)sprite_area.width) <= x) continue; 
+      if ((sprite_area.y+(int)sprite_area.height) <= y) continue;
+
+      ply_frame_buffer_fill_with_argb32_data_at_opacity_with_clip (frame_buffer,
+                                             &sprite_area, &clip_area, 0, 0,
+                                             ply_image_get_data (sprite->image), sprite->opacity);
+    }
+  ply_frame_buffer_unpause_updates (frame_buffer);
+}
+
+
+script_lib_sprite_data_t* script_lib_sprite_setup(script_state *state, ply_window_t   *window)
+{
+ script_lib_sprite_data_t* data = malloc(sizeof(script_lib_sprite_data_t));
+ data->class = script_obj_native_class_new(sprite_free, "sprite", data);
+ data->sprite_list = ply_list_new();
+ data->window = window;
+
+ script_add_native_function (state->global, "SpriteNew", sprite_new, data, NULL);
+ script_add_native_function (state->global, "SpriteSetImage", sprite_set_image, data, "sprite", "image", NULL);
+ script_add_native_function (state->global, "SpriteSetX", sprite_set_x, data, "sprite", "value", NULL);
+ script_add_native_function (state->global, "SpriteSetY", sprite_set_y, data, "sprite", "value", NULL);
+ script_add_native_function (state->global, "SpriteSetZ", sprite_set_z, data, "sprite", "value", NULL);
+
+ data->script_main_op = script_parse_string (script_lib_sprite_string);
+ script_return ret = script_execute(state, data->script_main_op);
+ if (ret.object) script_obj_unref(ret.object);                  // Throw anything sent back away
+
+ {
+ ply_frame_buffer_area_t screen_area;
+ ply_frame_buffer_t *frame_buffer = ply_window_get_frame_buffer (data->window);
+ ply_frame_buffer_get_size (frame_buffer, &screen_area);
+ draw_area (data, screen_area.x, screen_area.y, screen_area.width, screen_area.height);
+ }
+ return data;
+}
+
+
+void script_lib_sprite_refresh(script_lib_sprite_data_t* data)
+{
+ ply_list_node_t *node;
+ for(node = ply_list_get_first_node (data->sprite_list); node; node = ply_list_get_next_node (data->sprite_list, node)){
+    sprite_t* sprite = ply_list_node_get_data (node);
+    if (!sprite->image) continue;
+    if (sprite->x != sprite->old_x || sprite->y != sprite->old_y || sprite->z != sprite->old_z || sprite->old_opacity != sprite->opacity || sprite->refresh_me){
+        int width = ply_image_get_width (sprite->image);
+        int height= ply_image_get_height (sprite->image);
+        draw_area (data, sprite->x, sprite->y, width, height);
+        draw_area (data, sprite->old_x, sprite->old_y, width, height);
+        sprite->old_x = sprite->x;
+        sprite->old_y = sprite->y;
+        sprite->old_z = sprite->z;
+        sprite->old_opacity = sprite->opacity;
+        }
+    }
+}
+
+
+
+
+void script_lib_sprite_destroy(script_lib_sprite_data_t* data)
+{
+ script_obj_native_class_destroy(data->class);
+ ply_list_free(data->sprite_list);
+ script_parse_op_free (data->script_main_op);
+ free(data);
+}
+
+
+
diff --git a/src/plugins/splash/script/script-lib-sprite.h b/src/plugins/splash/script/script-lib-sprite.h
new file mode 100644 (file)
index 0000000..8f33f58
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef SCRIPT_LIB_SPRITE
+#define SCRIPT_LIB_SPRITE
+
+#include "script.h"
+
+typedef struct
+{
+  ply_window_t   *window;
+  ply_list_t     *sprite_list;
+  script_obj_native_class* class;
+  script_op      *script_main_op;
+} script_lib_sprite_data_t;
+
+
+typedef struct
+{
+  int x; 
+  int y;
+  int z;
+  float opacity;
+  int old_x; 
+  int old_y;
+  int old_z;
+  float old_opacity;
+  bool refresh_me;
+  ply_image_t *image;
+  script_obj *image_obj;
+} sprite_t;
+
+
+script_lib_sprite_data_t* script_lib_sprite_setup(script_state *state, ply_window_t *window);
+void script_lib_sprite_refresh(script_lib_sprite_data_t* data);
+void script_lib_sprite_destroy(script_lib_sprite_data_t* data);
+
+#endif /* SCRIPT_LIB_SPRITE */
diff --git a/src/plugins/splash/script/script-lib-sprite.script b/src/plugins/splash/script/script-lib-sprite.script
new file mode 100644 (file)
index 0000000..f8fddfa
--- /dev/null
@@ -0,0 +1,25 @@
+fun SpriteUpdate(sprite){
+    SpriteSetX(sprite.native, sprite.x);
+    SpriteSetY(sprite.native, sprite.y);
+    SpriteSetZ(sprite.native, sprite.z);
+    }
+
+
+fun SpriteNewWithImage(filename){
+    local.sprite;
+    
+    sprite.image = ImageNew(filename);
+    sprite.native = SpriteNew();
+    if (sprite.image == NULL) return NULL;
+    SpriteSetImage(sprite.native, sprite.image);
+    
+    sprite.x = 0;
+    sprite.y = 0;
+    sprite.z = 0;
+    
+    SpriteUpdate(sprite);
+    
+    return sprite;
+    }
+
+
diff --git a/src/plugins/splash/script/script-object.c b/src/plugins/splash/script/script-object.c
new file mode 100644 (file)
index 0000000..c63dc7c
--- /dev/null
@@ -0,0 +1,385 @@
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "script.h"
+#include "script-object.h"
+
+char* script_obj_print (script_obj* obj);
+void script_obj_reset (script_obj* obj);
+
+
+void script_obj_free (script_obj* obj)
+{
+ assert(!obj->refcount);
+ script_obj_reset (obj);
+ free(obj);
+}
+
+
+void script_obj_ref (script_obj* obj)
+{
+ obj->refcount++;
+}
+
+void script_obj_unref (script_obj* obj)
+{
+ obj->refcount--;
+ if (obj->refcount<=0){
+    script_obj_free (obj);
+    }
+}
+
+static void foreach_free_vareable (void *key,
+                                   void *data,
+                                   void *user_data)
+{
+ script_vareable* vareable = data;
+ script_obj_unref(vareable->object);
+ free(vareable->name);
+ free(vareable);
+}
+
+
+
+void script_obj_reset (script_obj* obj)
+{
+ switch (obj->type){
+    case SCRIPT_OBJ_TYPE_REF:
+        script_obj_unref (obj->data.obj);
+        break;
+    case SCRIPT_OBJ_TYPE_INT:
+        break;
+    case SCRIPT_OBJ_TYPE_STRING:
+        free(obj->data.string);
+        break;
+    case SCRIPT_OBJ_TYPE_HASH:                  // FIXME nightmare
+        ply_hashtable_foreach (obj->data.hash, foreach_free_vareable, NULL);
+        ply_hashtable_free(obj->data.hash);
+        break;
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+        {
+        if (obj->data.function->freeable){
+            ply_list_node_t *node;
+            for (node = ply_list_get_first_node (obj->data.function->parameters);
+                 node;
+                 node = ply_list_get_next_node (obj->data.function->parameters, node)){
+                char* operand = ply_list_node_get_data (node);
+                free(operand);
+                }
+            ply_list_free(obj->data.function->parameters);
+            free(obj->data.function);
+            }
+        }
+        break;
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        if (obj->data.native.class->free_func)
+            obj->data.native.class->free_func(obj);
+        
+        break;
+    case SCRIPT_OBJ_TYPE_NULL:
+        break;
+    }
+ obj->type = SCRIPT_OBJ_TYPE_NULL;
+}
+
+script_obj* script_obj_deref_direct (script_obj* obj)
+{
+ while (obj->type == SCRIPT_OBJ_TYPE_REF){
+    obj = obj->data.obj;
+    }
+ return obj;
+}
+
+void script_obj_deref (script_obj** obj_ptr)
+{
+ script_obj* obj = *obj_ptr;
+ obj = script_obj_deref_direct(obj);
+ script_obj_ref (obj);
+ script_obj_unref (*obj_ptr);
+ *obj_ptr = obj;
+}
+
+
+static void foreach_print_vareable (void *key,
+                                    void *data,
+                                    void *user_data)
+{
+ script_vareable* vareable = data;
+ char* string = script_obj_print (vareable->object);
+ char* reply;
+ char* prev = *(char**)user_data;
+ if (!prev) prev = strdup("");
+ asprintf(&reply, "%s%s = %s\n", prev, vareable->name, string);
+ free(string);
+ free(prev);
+ *(char**)user_data = reply;
+}
+
+
+
+
+char* script_obj_print (script_obj* obj)
+{
+ char* reply;
+ switch (obj->type){
+    case SCRIPT_OBJ_TYPE_REF:
+        {
+        char* subobj = script_obj_print (obj->data.obj);
+        asprintf(&reply, "->[%d]%s", obj->refcount, subobj);
+        free(subobj);
+        return reply;
+        }
+    
+    case SCRIPT_OBJ_TYPE_INT:
+        {
+        asprintf(&reply, "%d[%d]", obj->data.integer, obj->refcount);
+        return reply;
+        }
+    case SCRIPT_OBJ_TYPE_STRING:
+        {
+        asprintf(&reply, "\"%s\"[%d]", obj->data.string, obj->refcount);
+        return reply;
+        }
+    case SCRIPT_OBJ_TYPE_NULL:
+        {
+        asprintf(&reply, "NULL[%d]", obj->refcount);
+        return reply;
+        }
+    case SCRIPT_OBJ_TYPE_HASH:
+        {
+        char* sub = NULL;
+        ply_hashtable_foreach (obj->data.hash, foreach_print_vareable, &sub);
+        asprintf(&reply, "HASH{\n%s}[%d]", sub, obj->refcount);
+        free(sub);
+        return reply;
+        }
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+        {
+        asprintf(&reply, "function()[%d]", obj->refcount);
+        return reply;
+        }
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        {
+        asprintf(&reply, "(%s)[%d]", obj->data.native.class->name, obj->refcount);
+        return reply;
+        }
+    
+    default:
+        printf("unhandeled object type %d\n", obj->type);
+        assert(0);
+    }
+ return NULL;
+}
+
+
+
+script_obj* script_obj_new_int (int number)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_INT;
+ obj->refcount = 1;
+ obj->data.integer = number;
+ return obj;
+}
+
+script_obj* script_obj_new_string (const char* string)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_STRING;
+ obj->refcount = 1;
+ obj->data.string = strdup(string);
+ return obj;
+}
+
+script_obj* script_obj_new_null (void)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_NULL;
+ obj->refcount = 1;
+ return obj;
+}
+
+script_obj* script_obj_new_hash (void)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_HASH;
+ obj->data.hash = ply_hashtable_new (ply_hashtable_string_hash, ply_hashtable_string_compare);
+ obj->refcount = 1;
+ return obj;
+}
+
+script_obj* script_obj_new_function (script_function* function)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_FUNCTION;
+ obj->data.function = function;
+ obj->refcount = 1;
+ return obj;
+}
+
+script_obj* script_obj_new_ref (script_obj* sub_obj)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_REF;
+ obj->data.obj = sub_obj;
+ obj->refcount = 1;
+ return obj;
+}
+
+
+script_obj* script_obj_new_native (void* object_data, script_obj_native_class* class)
+{
+ script_obj* obj = malloc(sizeof(script_obj));
+ obj->type = SCRIPT_OBJ_TYPE_NATIVE;
+ obj->data.native.class = class;
+ obj->data.native.object_data = object_data;
+ obj->refcount = 1;
+ return obj;
+}
+
+int script_obj_as_int (script_obj* obj)
+{                                                     // If in then reply contents, otherwise reply 0
+ obj = script_obj_deref_direct(obj);
+ switch (obj->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        if (obj->data.integer) return obj->data.integer;
+        else return 0;
+    case SCRIPT_OBJ_TYPE_NULL:
+        return 0;
+    case SCRIPT_OBJ_TYPE_REF:       // should have been de-reffed already
+        assert(0);
+    case SCRIPT_OBJ_TYPE_HASH:
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        return 0;
+    case SCRIPT_OBJ_TYPE_STRING:
+        if (*obj->data.string) return true;
+        return 0;
+    }
+    
+ assert(0);         // Abort on uncaught
+ return false;
+}
+
+bool script_obj_as_bool (script_obj* obj)
+{                                                 // False objects are NULL, 0, ""
+ obj = script_obj_deref_direct(obj);
+ switch (obj->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        if (obj->data.integer) return true;
+        return false;
+    case SCRIPT_OBJ_TYPE_NULL:
+        return false;
+    case SCRIPT_OBJ_TYPE_REF:       // should have been de-reffed already
+        assert(0);
+    case SCRIPT_OBJ_TYPE_HASH:
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        return true;
+    case SCRIPT_OBJ_TYPE_STRING:
+        if (*obj->data.string) return true;
+        return false;
+    }
+    
+ assert(0);         // Abort on uncaught
+ return false;
+}
+
+
+char* script_obj_as_string (script_obj* obj)              // reply is strdupped
+{
+ obj = script_obj_deref_direct(obj);
+ char* reply;
+  
+ switch (obj->type){
+    case SCRIPT_OBJ_TYPE_INT:
+        asprintf(&reply, "%d", obj->data.integer);
+        return reply;
+    case SCRIPT_OBJ_TYPE_NULL:
+        asprintf(&reply, "NULL");
+        return reply;
+    case SCRIPT_OBJ_TYPE_REF:       // should have been de-reffed already
+        assert(0);
+    case SCRIPT_OBJ_TYPE_HASH:
+        assert(0);                  // FIXME decide
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+        assert(0);                  // FIXME decide
+    case SCRIPT_OBJ_TYPE_STRING:
+        return strdup(obj->data.string);
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        assert(0);                  // FIXME decide
+    }
+    
+ assert(0);         // Abort on uncaught
+ return false;
+}
+
+void script_obj_assign (script_obj* obj_a, script_obj* obj_b)
+{
+ script_obj_deref (&obj_b);
+ script_obj_reset (obj_a);
+ switch (obj_b->type){
+    case SCRIPT_OBJ_TYPE_NULL:
+        obj_a->type = SCRIPT_OBJ_TYPE_NULL;
+        break;
+    case SCRIPT_OBJ_TYPE_INT:
+        obj_a->type = SCRIPT_OBJ_TYPE_INT;
+        obj_a->data.integer = obj_b->data.integer;
+        break;
+    case SCRIPT_OBJ_TYPE_STRING:
+        obj_a->type = SCRIPT_OBJ_TYPE_STRING;
+        obj_a->data.string = strdup(obj_b->data.string);
+        break;
+    case SCRIPT_OBJ_TYPE_REF:       // should have been de-reffed already
+        assert(0);
+    case SCRIPT_OBJ_TYPE_HASH:
+    case SCRIPT_OBJ_TYPE_FUNCTION:
+    case SCRIPT_OBJ_TYPE_NATIVE:
+        obj_a->type = SCRIPT_OBJ_TYPE_REF;
+        obj_a->data.obj = obj_b;
+        script_obj_ref(obj_b);
+        break;
+    }
+}
+
+script_obj* script_obj_hash_get_element (script_obj* hash, const char* name)
+{
+ assert(hash->type == SCRIPT_OBJ_TYPE_HASH);
+ script_vareable* vareable = ply_hashtable_lookup (hash->data.hash, (void*)name);
+ script_obj* obj;
+ if (vareable) {
+    obj = vareable->object;
+    }
+ else {
+    obj = script_obj_new_null ();
+    vareable = malloc(sizeof(script_vareable));
+    vareable->name = strdup(name);
+    vareable->object = obj;
+    ply_hashtable_insert (hash->data.hash, vareable->name, vareable);
+    }
+ script_obj_ref (obj);
+ return obj;
+}
+
+
+void script_obj_hash_add_element (script_obj* hash, script_obj* element, const char* name)
+{
+ assert(hash->type == SCRIPT_OBJ_TYPE_HASH);
+ script_obj* obj = script_obj_hash_get_element (hash, name);
+ script_obj_assign (obj, element);
+ script_obj_unref (obj);
+}
+
diff --git a/src/plugins/splash/script/script-object.h b/src/plugins/splash/script/script-object.h
new file mode 100644 (file)
index 0000000..5e79d43
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef SCRIPT_OBJECT
+#define SCRIPT_OBJECT
+
+#include "script.h"
+
+void script_obj_free (script_obj* obj);
+void script_obj_ref (script_obj* obj);
+void script_obj_unref (script_obj* obj);
+void script_obj_reset (script_obj* obj);
+script_obj* script_obj_deref_direct (script_obj* obj);
+void script_obj_deref (script_obj** obj_ptr);
+char* script_obj_print (script_obj* obj);
+script_obj* script_obj_new_int (int number);
+script_obj* script_obj_new_string (const char* string);
+script_obj* script_obj_new_null (void);
+script_obj* script_obj_new_hash (void);
+script_obj* script_obj_new_function (script_function* function);
+script_obj* script_obj_new_ref (script_obj* sub_obj);
+script_obj* script_obj_new_native (void* object_data, script_obj_native_class* class);
+int script_obj_as_int (script_obj* obj);
+bool script_obj_as_bool (script_obj* obj);
+char* script_obj_as_string (script_obj* obj);
+void script_obj_assign (script_obj* obj_a, script_obj* obj_b);
+script_obj* script_obj_hash_get_element (script_obj* hash, const char* name);
+void script_obj_hash_add_element (script_obj* hash, script_obj* element, const char* name);
+
+
+#endif /* SCRIPT_OBJECT */
diff --git a/src/plugins/splash/script/script-parse.c b/src/plugins/splash/script/script-parse.c
new file mode 100644 (file)
index 0000000..cd57511
--- /dev/null
@@ -0,0 +1,646 @@
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "script.h"
+#include "script-parse.h"
+
+
+#define WITH_SEMIES
+
+
+
+
+/*                          done    todo
+int var (exp)           tm   =      ! ++ -- 
+f() f[] f.a             pi   =      
+* / %                   md   =
++ -                     pm   =      && || 
+< <= > >=               gt   =
+== !=                   eq   =
+=                       as   =      += -= *= %=
+
+*/
+
+
+static script_op* script_parse_op (ply_scan_t* scan);
+static script_exp* script_parse_exp (ply_scan_t* scan);
+static ply_list_t* script_parse_op_list (ply_scan_t* scan);
+static void script_parse_op_list_free (ply_list_t* op_list);
+
+static script_exp* script_parse_exp_tm (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ script_exp* exp = NULL;
+ if (curtoken->type == PLY_SCAN_TOKEN_TYPE_INTEGER){
+    exp = malloc(sizeof(script_exp));
+    exp->type = SCRIPT_EXP_TYPE_TERM_INT;
+    exp->data.integer = curtoken->data.integer;
+    ply_scan_get_next_token(scan);
+    return exp;
+    }
+ if (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER){
+    exp = malloc(sizeof(script_exp));
+    if (!strcmp(curtoken->data.string, "NULL")){
+        exp->type = SCRIPT_EXP_TYPE_TERM_NULL;
+        }
+    else if (!strcmp(curtoken->data.string, "global")){
+        exp->type = SCRIPT_EXP_TYPE_TERM_GLOBAL;
+        }
+    else if (!strcmp(curtoken->data.string, "local")){
+        exp->type = SCRIPT_EXP_TYPE_TERM_LOCAL;
+        }
+    else {
+        exp->type = SCRIPT_EXP_TYPE_TERM_VAR;
+        exp->data.string = strdup(curtoken->data.string);
+        }
+    curtoken = ply_scan_get_next_token(scan);
+    return exp;
+    }
+ if (curtoken->type == PLY_SCAN_TOKEN_TYPE_STRING){
+    exp = malloc(sizeof(script_exp));
+    exp->type = SCRIPT_EXP_TYPE_TERM_STRING;
+    exp->data.string = strdup(curtoken->data.string);
+    ply_scan_get_next_token(scan);
+    return exp;
+    }
+ if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == '('){
+    ply_scan_get_next_token(scan);
+    exp = script_parse_exp (scan);
+    assert(exp);                                        //FIXME syntax error
+    curtoken = ply_scan_get_current_token(scan);
+    assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')');
+    ply_scan_get_next_token(scan);
+    return exp;
+    }
+ return exp;
+}
+
+static script_exp* script_parse_exp_pi (ply_scan_t* scan)
+{
+ script_exp* exp = script_parse_exp_tm (scan);
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ while (true){
+    if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
+    if (curtoken->data.symbol == '('){
+        script_exp* func = malloc(sizeof(script_exp));
+        ply_list_t* parameters = ply_list_new();
+        ply_scan_get_next_token(scan);
+        while (true){
+            if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')') break;
+
+            script_exp* parameter = script_parse_exp (scan);
+
+            ply_list_append_data (parameters, parameter);
+
+            curtoken = ply_scan_get_current_token(scan);
+            assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+            if (curtoken->data.symbol == ')') break;
+            assert (curtoken->data.symbol == ',');                      //FIXME syntax error
+            ply_scan_get_next_token(scan);
+            }
+        ply_scan_get_next_token(scan);
+        func->data.function.name = exp;
+        exp = func;
+        exp->type = SCRIPT_EXP_TYPE_FUNCTION;
+        exp->data.function.parameters = parameters;
+        continue;
+        }
+
+    script_exp* key;
+
+    if (curtoken->data.symbol == '.'){
+        ply_scan_get_next_token(scan);
+        if (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER){
+            key = malloc(sizeof(script_exp));
+            key->type = SCRIPT_EXP_TYPE_TERM_STRING;
+            key->data.string = strdup(curtoken->data.string);
+            }
+        else if (curtoken->type == PLY_SCAN_TOKEN_TYPE_INTEGER){        // errrr, integer keys without being [] bracketted
+            key = malloc(sizeof(script_exp));                           // This is broken with floats as obj.10.6 is obj[10.6] and not obj[10][6]
+            key->type = SCRIPT_EXP_TYPE_TERM_INT;
+            key->data.integer = curtoken->data.integer;
+            }
+        else assert(0);                                                 //FIXME syntax error
+        curtoken = ply_scan_get_next_token(scan);
+        }
+    else if (curtoken->data.symbol == '['){
+        ply_scan_get_next_token(scan);
+        key = script_parse_exp (scan);
+        curtoken = ply_scan_get_current_token(scan);
+        assert (curtoken->data.symbol == ']');
+        curtoken = ply_scan_get_next_token(scan);
+        }
+    else break;
+    script_exp* hash = malloc(sizeof(script_exp));
+    hash->type = SCRIPT_EXP_TYPE_HASH;
+    hash->data.dual.sub_a = exp;
+    hash->data.dual.sub_b = key;
+    exp = hash;                                         // common hash lookup bit;
+
+
+    }
+ return exp;
+}
+
+
+
+
+static script_exp* script_parse_exp_md (ply_scan_t* scan)
+{
+ script_exp* sub_a = script_parse_exp_pi (scan);
+ if (!sub_a) return NULL;
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL &&
+            (curtoken->data.symbol == '*' ||
+             curtoken->data.symbol == '/' ||
+             curtoken->data.symbol == '%' )){
+    script_exp* exp = malloc(sizeof(script_exp));
+    if (curtoken->data.symbol == '*')       exp->type = SCRIPT_EXP_TYPE_MUL;
+    else if (curtoken->data.symbol == '/')  exp->type = SCRIPT_EXP_TYPE_DIV;
+    else                                    exp->type = SCRIPT_EXP_TYPE_MOD;
+    exp->data.dual.sub_a = sub_a;
+    ply_scan_get_next_token(scan);
+    exp->data.dual.sub_b = script_parse_exp_pi (scan);
+    assert(exp->data.dual.sub_b);                                        //FIXME syntax error
+    sub_a = exp;
+    curtoken = ply_scan_get_current_token(scan);
+    }
+ return sub_a;
+}
+
+static script_exp* script_parse_exp_pm (ply_scan_t* scan)
+{
+ script_exp* sub_a = script_parse_exp_md (scan);
+ if (!sub_a) return NULL; 
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL &&
+            (curtoken->data.symbol == '+' ||
+             curtoken->data.symbol == '-' )){
+    script_exp* exp = malloc(sizeof(script_exp));
+    if (curtoken->data.symbol == '+')   exp->type = SCRIPT_EXP_TYPE_PLUS;
+    else                                exp->type = SCRIPT_EXP_TYPE_MINUS;
+    exp->data.dual.sub_a = sub_a;
+    ply_scan_get_next_token(scan);
+    exp->data.dual.sub_b = script_parse_exp_md (scan);
+    assert(exp->data.dual.sub_b);                                        //FIXME syntax error
+    sub_a = exp;
+    curtoken = ply_scan_get_current_token(scan);
+    }
+ return sub_a;
+}
+
+static script_exp* script_parse_exp_gt (ply_scan_t* scan)
+{
+ script_exp* sub_a = script_parse_exp_pm (scan);
+ if (!sub_a) return NULL; 
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
+ while (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL &&
+            (curtoken->data.symbol == '<' ||
+             curtoken->data.symbol == '>' )){                           // FIXME make sure we dont consume <<= or >>=
+    int gt = (curtoken->data.symbol == '>');
+    int eq = 0;
+    curtoken = ply_scan_get_next_token(scan);
+    if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && 
+             curtoken->data.symbol == '='){
+        eq = 1;
+        curtoken = ply_scan_get_next_token(scan);
+        }
+    script_exp* exp = malloc(sizeof(script_exp));
+    if      ( gt &&  eq) exp->type = SCRIPT_EXP_TYPE_GE;
+    else if ( gt && !eq) exp->type = SCRIPT_EXP_TYPE_GT;
+    else if (!gt &&  eq) exp->type = SCRIPT_EXP_TYPE_LE;
+    else                 exp->type = SCRIPT_EXP_TYPE_LT;
+    
+    exp->data.dual.sub_a = sub_a;
+    exp->data.dual.sub_b = script_parse_exp_pm (scan);
+    assert(exp->data.dual.sub_b);                                        //FIXME syntax error
+    sub_a = exp;
+    curtoken = ply_scan_get_current_token(scan);
+    peektoken = ply_scan_peek_next_token(scan);
+    }
+ return sub_a;
+}
+
+static script_exp* script_parse_exp_eq (ply_scan_t* scan)
+{
+ script_exp* sub_a = script_parse_exp_gt (scan);
+ if (!sub_a) return NULL; 
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ ply_scan_token_t* peektoken = ply_scan_peek_next_token(scan);
+ while (1){
+    if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
+    if (peektoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL) break;
+    
+    if (peektoken->data.symbol != '=') break;
+    if ((curtoken->data.symbol != '=') && (curtoken->data.symbol != '!')) break;
+    int ne = (curtoken->data.symbol == '!');
+    ply_scan_get_next_token(scan);
+    ply_scan_get_next_token(scan);
+    
+    script_exp* exp = malloc(sizeof(script_exp));
+    if (ne)   exp->type = SCRIPT_EXP_TYPE_NE;
+    else      exp->type = SCRIPT_EXP_TYPE_EQ;
+    exp->data.dual.sub_a = sub_a;
+    exp->data.dual.sub_b = script_parse_exp_gt (scan);
+    assert(exp->data.dual.sub_b);                                        //FIXME syntax error
+    sub_a = exp;
+    curtoken = ply_scan_get_current_token(scan);
+    peektoken = ply_scan_peek_next_token(scan);
+    }
+ return sub_a;
+}
+
+static script_exp* script_parse_exp_as (ply_scan_t* scan)
+{
+ script_exp* lhs = script_parse_exp_eq (scan);
+ if (!lhs) return NULL; 
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == '=' ){
+    ply_scan_get_next_token(scan);
+    script_exp* rhs = script_parse_exp_eq(scan);
+    assert(rhs);                                        //FIXME syntax error
+    script_exp* exp = malloc(sizeof(script_exp));
+    exp->type = SCRIPT_EXP_TYPE_ASSIGN;
+    exp->data.dual.sub_a = lhs;
+    exp->data.dual.sub_b = rhs;
+    return exp;
+    }
+ return lhs;
+}
+
+static script_exp* script_parse_exp (ply_scan_t* scan)
+{
+ return script_parse_exp_as (scan);
+}
+
+static script_op* script_parse_op_block (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ if (curtoken->type != PLY_SCAN_TOKEN_TYPE_SYMBOL  || curtoken->data.symbol != '{' )
+    return NULL;
+ ply_scan_get_next_token(scan);
+ ply_list_t* sublist = script_parse_op_list (scan);
+ assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+ assert(curtoken->data.symbol == '}');
+ curtoken = ply_scan_get_next_token(scan);
+
+ script_op* op = malloc(sizeof(script_op));
+ op->type = SCRIPT_OP_TYPE_OP_BLOCK;
+ op->data.list = sublist;
+ return op;
+}
+
+static script_op* script_parse_if_while (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ script_op_type type;
+ if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER)
+    return NULL;
+ if       (!strcmp(curtoken->data.string, "if"))    type = SCRIPT_OP_TYPE_IF;
+ else if  (!strcmp(curtoken->data.string, "while")) type = SCRIPT_OP_TYPE_WHILE;
+ else return NULL;
+ curtoken = ply_scan_get_next_token(scan);
+ assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+ assert(curtoken->data.symbol == '(');
+ curtoken = ply_scan_get_next_token(scan);
+ script_exp* cond = script_parse_exp (scan);
+ assert(cond);                                               //FIXME syntax error
+ curtoken = ply_scan_get_current_token(scan);
+ assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+ assert(curtoken->data.symbol == ')');
+ curtoken = ply_scan_get_next_token(scan);
+ script_op* cond_op = script_parse_op(scan);
+ script_op* op = malloc(sizeof(script_op));
+ op->type = type;
+ op->data.cond_op.cond = cond;
+ op->data.cond_op.op = cond_op;
+ return op;
+}
+
+
+
+
+
+static script_op* script_parse_function (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ ply_list_t *parameter_list;
+ if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER)
+    return NULL;
+ if (strcmp(curtoken->data.string, "fun")) return NULL;
+ curtoken = ply_scan_get_next_token(scan);
+ assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER);       //FIXME syntax error
+ script_exp* name = malloc(sizeof(script_exp));
+ name->type = SCRIPT_EXP_TYPE_TERM_VAR;
+ name->data.string = strdup(curtoken->data.string);
+
+ curtoken = ply_scan_get_next_token(scan);
+ assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+ assert(curtoken->data.symbol == '(');
+ curtoken = ply_scan_get_next_token(scan);
+ parameter_list = ply_list_new();
+ while (true){
+    if (curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL && curtoken->data.symbol == ')') break;
+    assert (curtoken->type == PLY_SCAN_TOKEN_TYPE_IDENTIFIER);
+    char* parameter = strdup(curtoken->data.string);
+    ply_list_append_data (parameter_list, parameter);
+    
+    curtoken = ply_scan_get_next_token(scan);
+    assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);       //FIXME syntax error
+    if (curtoken->data.symbol == ')') break;
+    assert (curtoken->data.symbol == ',');                      //FIXME syntax error
+    ply_scan_get_next_token(scan);
+    }
+ curtoken = ply_scan_get_next_token(scan);
+ script_op* func_op = script_parse_op(scan);
+
+ script_op* op = malloc(sizeof(script_op));
+ op->type = SCRIPT_OP_TYPE_FUNCTION_DEF;
+ op->data.function_def.name = name;
+ op->data.function_def.function = script_function_script_new(func_op, NULL, parameter_list);
+ return op;
+}
+
+
+
+
+static script_op* script_parse_return (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ if (curtoken->type != PLY_SCAN_TOKEN_TYPE_IDENTIFIER)
+    return NULL;
+ script_op_type type;
+ if      (!strcmp(curtoken->data.string, "return"))   type = SCRIPT_OP_TYPE_RETURN;
+ else if (!strcmp(curtoken->data.string, "break"))    type = SCRIPT_OP_TYPE_BREAK;
+ else if (!strcmp(curtoken->data.string, "continue")) type = SCRIPT_OP_TYPE_CONTINUE;
+ else return NULL;
+ curtoken = ply_scan_get_next_token(scan);
+ script_op* op = malloc(sizeof(script_op));
+ if (type == SCRIPT_OP_TYPE_RETURN){
+    op->data.exp = script_parse_exp (scan);                    // May be NULL
+    curtoken = ply_scan_get_current_token(scan);
+    }
+
+#ifdef WITH_SEMIES
+    assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);
+    assert(curtoken->data.symbol == ';');
+    curtoken = ply_scan_get_next_token(scan);
+#endif
+
+ op->type = type;
+ return op;
+}
+
+
+
+
+
+
+
+
+static script_op* script_parse_op (ply_scan_t* scan)
+{
+ ply_scan_token_t* curtoken = ply_scan_get_current_token(scan);
+ script_op* reply = NULL;
+ reply = script_parse_op_block (scan);
+ if (reply) return reply;
+ reply = script_parse_if_while (scan);
+ if (reply) return reply;
+
+ reply = script_parse_return (scan);
+ if (reply) return reply;
+
+ reply = script_parse_function (scan);
+ if (reply) return reply;
+
+// if curtoken->data.string == "if/for/while...
+
+
+// default is expression
+    {
+    script_exp* exp = script_parse_exp(scan);
+    if (!exp) return NULL;
+    curtoken = ply_scan_get_current_token(scan);
+#ifdef WITH_SEMIES
+    assert(curtoken->type == PLY_SCAN_TOKEN_TYPE_SYMBOL);
+    assert(curtoken->data.symbol == ';');
+    curtoken = ply_scan_get_next_token(scan);
+#endif
+
+    script_op* op = malloc(sizeof(script_op));
+    op->type = SCRIPT_OP_TYPE_EXPRESSION;
+    op->data.exp = exp;
+    return op;
+    }
+ return NULL;
+}
+
+static ply_list_t* script_parse_op_list (ply_scan_t* scan)
+{
+ ply_list_t *op_list = ply_list_new();
+ while(1){
+    script_op* op = script_parse_op (scan);
+    if (!op) break;
+    ply_list_append_data (op_list, op);
+    }
+ return op_list;
+}
+
+static void script_parse_exp_free (script_exp* exp)
+{
+ if (!exp) return;
+ switch (exp->type){
+    case SCRIPT_EXP_TYPE_PLUS:
+    case SCRIPT_EXP_TYPE_MINUS:
+    case SCRIPT_EXP_TYPE_MUL:
+    case SCRIPT_EXP_TYPE_DIV:
+    case SCRIPT_EXP_TYPE_MOD:
+    case SCRIPT_EXP_TYPE_EQ:
+    case SCRIPT_EXP_TYPE_NE:
+    case SCRIPT_EXP_TYPE_GT:
+    case SCRIPT_EXP_TYPE_GE:
+    case SCRIPT_EXP_TYPE_LT:
+    case SCRIPT_EXP_TYPE_LE:
+    case SCRIPT_EXP_TYPE_ASSIGN:
+    case SCRIPT_EXP_TYPE_HASH:
+        script_parse_exp_free (exp->data.dual.sub_a);
+        script_parse_exp_free (exp->data.dual.sub_b);
+        break;
+    case SCRIPT_EXP_TYPE_TERM_INT:
+    case SCRIPT_EXP_TYPE_TERM_NULL:
+    case SCRIPT_EXP_TYPE_TERM_LOCAL:
+    case SCRIPT_EXP_TYPE_TERM_GLOBAL:
+        break;
+    case SCRIPT_EXP_TYPE_FUNCTION:
+        {
+        ply_list_node_t *node;
+        for (node = ply_list_get_first_node (exp->data.function.parameters);
+             node;
+             node = ply_list_get_next_node (exp->data.function.parameters, node)){
+            script_exp* sub = ply_list_node_get_data (node);
+            script_parse_exp_free (sub);
+            }
+        ply_list_free(exp->data.function.parameters);
+        script_parse_exp_free (exp->data.function.name);
+        break;
+        }
+    case SCRIPT_EXP_TYPE_TERM_STRING:
+    case SCRIPT_EXP_TYPE_TERM_VAR:
+        free (exp->data.string);
+        break;
+    }
+ free(exp);
+}
+
+
+
+void script_parse_op_free (script_op* op)
+{
+ switch (op->type){
+    case SCRIPT_OP_TYPE_EXPRESSION:
+        {
+        script_parse_exp_free (op->data.exp);
+        break;
+        }
+    case SCRIPT_OP_TYPE_OP_BLOCK:
+        {
+        script_parse_op_list_free (op->data.list);
+        break;
+        }
+    case SCRIPT_OP_TYPE_IF:
+    case SCRIPT_OP_TYPE_WHILE:
+        {
+        script_parse_exp_free (op->data.cond_op.cond);
+        script_parse_op_free  (op->data.cond_op.op);
+        break;
+        }
+        {
+        break;
+        }
+    case SCRIPT_OP_TYPE_FUNCTION_DEF:
+        {
+        if (op->data.function_def.function->type == SCRIPT_FUNCTION_TYPE_SCRIPT){
+            script_parse_op_free (op->data.function_def.function->data.script);
+            }
+        ply_list_node_t *node;
+        for (node = ply_list_get_first_node (op->data.function_def.function->parameters);
+             node;
+             node = ply_list_get_next_node (op->data.function_def.function->parameters, node)){
+            char* arg = ply_list_node_get_data (node);
+            free(arg);
+            }
+        ply_list_free(op->data.function_def.function->parameters);
+        script_parse_exp_free(op->data.function_def.name);
+        free(op->data.function_def.function);
+        break;
+        }
+    case SCRIPT_OP_TYPE_RETURN:
+        {
+        if (op->data.exp) script_parse_exp_free (op->data.exp);
+        break;
+        }
+    case SCRIPT_OP_TYPE_BREAK:
+    case SCRIPT_OP_TYPE_CONTINUE:
+        {
+        break;
+        }
+    }
+ free(op);
+}
+
+
+static void script_parse_op_list_free (ply_list_t* op_list)
+{
+ ply_list_node_t *node;
+ for (node = ply_list_get_first_node (op_list); node; node = ply_list_get_next_node (op_list, node)){
+    script_op* op = ply_list_node_get_data (node);
+    script_parse_op_free(op);
+    }
+ ply_list_free(op_list);
+ return;
+}
+
+
+
+
+script_op* script_parse_file (char* filename)
+{
+ ply_scan_t* scan = ply_scan_file (filename);
+ assert(scan);
+ ply_list_t* list = script_parse_op_list (scan);
+ ply_scan_free(scan);
+ script_op* op = malloc(sizeof(script_op));
+ op->type = SCRIPT_OP_TYPE_OP_BLOCK;
+ op->data.list = list;
+ return op;
+}
+
+
+
+
+
+
+
+script_op* script_parse_string (char* string)
+{
+ ply_scan_t* scan = ply_scan_string (string);
+ assert(scan);
+ ply_list_t* list = script_parse_op_list (scan);
+ ply_scan_free(scan);
+ script_op* op = malloc(sizeof(script_op));
+ op->type = SCRIPT_OP_TYPE_OP_BLOCK;
+ op->data.list = list;
+ return op;
+}
+
+
+
+
+
+
+
diff --git a/src/plugins/splash/script/script-parse.h b/src/plugins/splash/script/script-parse.h
new file mode 100644 (file)
index 0000000..04f1086
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SCRIPT_PARSE
+#define SCRIPT_PARSE
+
+#include "script.h"
+
+script_op* script_parse_file (char* filename);
+script_op* script_parse_string (char* string);
+void script_parse_op_free (script_op* op);
+
+
+
+#endif /* SCRIPT_PARSE */
diff --git a/src/plugins/splash/script/script.c b/src/plugins/splash/script/script.c
new file mode 100644 (file)
index 0000000..66b012a
--- /dev/null
@@ -0,0 +1,112 @@
+#define _GNU_SOURCE
+#include "ply-scan.h"
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-bitarray.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include "script.h"
+#include "script-parse.h"
+#include "script-object.h"
+
+
+
+
+script_function* script_function_script_new(script_op* script, void* user_data, ply_list_t* parameter_list)
+{
+ script_function* function = malloc(sizeof(script_function));
+ function->type = SCRIPT_FUNCTION_TYPE_SCRIPT;
+ function->parameters = parameter_list;
+ function->data.script = script;
+ function->freeable = false; 
+ function->user_data = user_data;
+ return function;
+}
+
+script_function* script_function_native_new(script_native_function native_function, void* user_data, ply_list_t* parameter_list)
+{
+ script_function* function = malloc(sizeof(script_function));
+ function->type = SCRIPT_FUNCTION_TYPE_NATIVE;
+ function->parameters = parameter_list;
+ function->data.native = native_function;
+ function->freeable = true;
+ function->user_data = user_data;
+ return function;
+}
+
+void script_add_native_function (script_obj *hash, const char* name, script_native_function native_function, void* user_data, const char* first_arg, ...)
+{
+ va_list args;
+ const char* arg;
+ ply_list_t *parameter_list = ply_list_new();
+  
+ arg = first_arg;
+ va_start (args, first_arg);
+ while (arg){
+    ply_list_append_data (parameter_list, strdup(arg));
+    arg = va_arg (args, const char*);
+    }
+ va_end (args);
+
+ script_function* function = script_function_native_new(native_function, user_data, parameter_list);
+ script_obj* obj = script_obj_new_function (function);
+ script_obj_hash_add_element (hash, obj, name);
+ script_obj_unref(obj);
+}
+
+
+script_obj_native_class* script_obj_native_class_new(script_obj_function free_func, const char* name, void* user_data)
+{
+ script_obj_native_class* class = malloc(sizeof(script_obj_native_class));
+ class->free_func = free_func;
+ class->name = strdup(name);
+ class->user_data = user_data;
+ return class;
+}
+
+
+
+void script_obj_native_class_destroy(script_obj_native_class* class)
+{
+ free(class->name);
+ free(class);
+ return;
+}
+
+script_state* script_state_new(void* user_data)
+{
+ script_state* state = malloc(sizeof(script_state));
+ state->global = script_obj_new_hash();
+ script_obj_ref(state->global);
+ state->local = state->global;
+ state->user_data = user_data;
+ return state;
+}
+
+script_state* script_state_init_sub(script_state* oldstate)
+{
+ script_state* newstate = malloc(sizeof(script_state));
+ newstate->global = oldstate->global;
+ script_obj_ref(newstate->global);
+ newstate->local = script_obj_new_hash();
+ newstate->user_data = oldstate->user_data;
+ return newstate;
+}
+
+void script_state_destroy(script_state* state)
+{
+ script_obj_unref(state->global);
+ script_obj_unref(state->local);
+ free(state);
+}
+
+
+
+
diff --git a/src/plugins/splash/script/script.h b/src/plugins/splash/script/script.h
new file mode 100644 (file)
index 0000000..8baa6e0
--- /dev/null
@@ -0,0 +1,192 @@
+#ifndef SCRIPT_H
+#define SCRIPT_H
+
+
+#include "ply-hashtable.h"
+#include "ply-list.h"
+#include "ply-scan.h"
+
+
+typedef enum                        // FIXME add _t to all types 
+{
+ SCRIPT_RETURN_TYPE_NORMAL,
+ SCRIPT_RETURN_TYPE_RETURN,
+ SCRIPT_RETURN_TYPE_BREAK,
+ SCRIPT_RETURN_TYPE_CONTINUE,
+} script_return_type;
+
+struct script_obj;
+
+typedef struct 
+{
+ script_return_type type;
+ struct script_obj* object;
+} script_return;
+
+typedef struct 
+{
+ void* user_data;
+ struct script_obj* global;
+ struct script_obj* local;
+} script_state;
+
+
+typedef enum
+{
+ SCRIPT_FUNCTION_TYPE_SCRIPT,
+ SCRIPT_FUNCTION_TYPE_NATIVE,
+} script_function_type;
+
+
+typedef script_return (*script_native_function) (script_state*, void*);
+
+typedef struct script_function
+{
+ script_function_type type;
+ ply_list_t* parameters;            //  list of char* typedef names
+ void * user_data;
+ union
+ {
+    script_native_function native;
+    struct script_op* script;
+ }data;
+ bool freeable;
+} script_function;
+
+typedef void (*script_obj_function) (struct script_obj*);
+
+typedef struct
+{
+ script_obj_function free_func;
+ char* name;
+ void* user_data;
+} script_obj_native_class;
+
+typedef struct
+{
+ void* object_data;
+ script_obj_native_class* class;
+} script_obj_native;
+
+typedef enum
+{
+ SCRIPT_OBJ_TYPE_NULL,
+ SCRIPT_OBJ_TYPE_REF,
+ SCRIPT_OBJ_TYPE_INT,
+ SCRIPT_OBJ_TYPE_STRING,
+ SCRIPT_OBJ_TYPE_HASH,
+ SCRIPT_OBJ_TYPE_FUNCTION,
+ SCRIPT_OBJ_TYPE_NATIVE,
+} script_obj_type;
+
+typedef struct script_obj
+{
+ script_obj_type type;
+ int refcount;
+ union
+ {
+    int integer;
+    char* string;
+    struct script_obj* obj;
+    script_function* function;
+    ply_hashtable_t* hash;
+    script_obj_native native;
+ } data;
+} script_obj;
+
+
+
+typedef enum
+{
+ SCRIPT_EXP_TYPE_TERM_NULL,
+ SCRIPT_EXP_TYPE_TERM_INT,
+ SCRIPT_EXP_TYPE_TERM_STRING,
+ SCRIPT_EXP_TYPE_TERM_VAR,
+ SCRIPT_EXP_TYPE_TERM_LOCAL,
+ SCRIPT_EXP_TYPE_TERM_GLOBAL,
+ SCRIPT_EXP_TYPE_PLUS,
+ SCRIPT_EXP_TYPE_MINUS,
+ SCRIPT_EXP_TYPE_MUL,
+ SCRIPT_EXP_TYPE_DIV,
+ SCRIPT_EXP_TYPE_MOD,
+ SCRIPT_EXP_TYPE_GT,
+ SCRIPT_EXP_TYPE_GE,
+ SCRIPT_EXP_TYPE_LT,
+ SCRIPT_EXP_TYPE_LE,
+ SCRIPT_EXP_TYPE_EQ,
+ SCRIPT_EXP_TYPE_NE,
+ SCRIPT_EXP_TYPE_HASH,
+ SCRIPT_EXP_TYPE_FUNCTION,
+ SCRIPT_EXP_TYPE_ASSIGN,
+} script_exp_type;
+
+
+typedef struct script_exp
+{
+ script_exp_type type;
+ union
+ {
+    struct {
+        struct script_exp* sub_a;
+        struct script_exp* sub_b;
+        } dual;
+    struct script_exp *sub;
+    char* string;
+    int integer; 
+    struct {
+        struct script_exp* name;
+        ply_list_t* parameters;
+        } function;
+ } data;
+} script_exp;
+
+
+
+
+typedef enum
+{
+ SCRIPT_OP_TYPE_EXPRESSION,
+ SCRIPT_OP_TYPE_OP_BLOCK,
+ SCRIPT_OP_TYPE_IF,
+ SCRIPT_OP_TYPE_WHILE,
+ SCRIPT_OP_TYPE_FUNCTION_DEF,
+ SCRIPT_OP_TYPE_RETURN,
+ SCRIPT_OP_TYPE_BREAK,
+ SCRIPT_OP_TYPE_CONTINUE,
+} script_op_type;
+
+typedef struct script_op
+{
+ script_op_type type;
+ union
+ {
+    script_exp* exp;
+    ply_list_t* list;
+    struct {
+        script_exp* cond;
+        struct script_op* op;
+        } cond_op;
+    struct {
+        script_exp* name;
+        script_function* function;
+        } function_def;
+ } data;
+} script_op;
+
+
+typedef struct 
+{
+ char* name;
+ script_obj* object;
+} script_vareable;
+
+script_function* script_function_script_new(script_op* script, void* user_data, ply_list_t* parameter_list);
+script_function* script_function_native_new(script_native_function native_function, void* user_data, ply_list_t* parameter_list);
+void script_add_native_function (script_obj *hash, const char* name, script_native_function native_function, void* user_data, const char* first_arg, ...);
+script_obj_native_class* script_obj_native_class_new(script_obj_function free_func, const char* name, void* user_data);
+void script_obj_native_class_destroy(script_obj_native_class* class);
+script_state* script_state_new(void* user_data);
+script_state* script_state_init_sub(script_state* oldstate);
+void script_state_destroy(script_state* state);
+
+#endif /* SCRIPT_H */
diff --git a/src/plugins/splash/script/stringify.pl b/src/plugins/splash/script/stringify.pl
new file mode 100755 (executable)
index 0000000..a0c3b45
--- /dev/null
@@ -0,0 +1,14 @@
+#! /bin/sh
+exec perl -x $0 ${1+"$@"}
+       if 0;
+#!perl
+
+print "static const char* STRINGIFY_VAR = ";
+while (<>)
+{
+       chomp;
+    s/\\/\\\\/g;
+    s/"/\\"/g;
+       print "\"$_\\n\"\n";
+}
+print ";";
index 3e5207dfba011c0d1459d47943f5ceb21ddd1958..3caa2e62471d5ae1bd79ff389951e585a743d23d 100644 (file)
@@ -1,2 +1,2 @@
-SUBDIRS = spinfinity fade-in text details solar glow
+SUBDIRS = spinfinity fade-in text details solar glow script
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/themes/script/Makefile.am b/themes/script/Makefile.am
new file mode 100644 (file)
index 0000000..b66a801
--- /dev/null
@@ -0,0 +1,14 @@
+themedir = $(datadir)/plymouth/themes/script
+dist_theme_DATA =                                                     \
+                    script.plymouth                                   \
+                    script.script
+
+
+MAINTAINERCLEANFILES = Makefile.in script.plymouth
+CLEANFILES = script.plymouth
+
+script.plymouth: $(srcdir)/script.plymouth.in
+       sed -e 's,[@]PLYMOUTH_THEME_PATH[@],$(PLYMOUTH_THEME_PATH),g' \
+              $(srcdir)/script.plymouth.in > script.plymouth
+
+EXTRA_DIST = script.plymouth.in
diff --git a/themes/script/script.plymouth.in b/themes/script/script.plymouth.in
new file mode 100644 (file)
index 0000000..8d916b5
--- /dev/null
@@ -0,0 +1,8 @@
+[Plymouth Theme]
+Name=Script
+Description=Script plugin. not much here atm
+ModuleName=script
+
+[script]
+ImageDir=@PLYMOUTH_THEME_PATH@/script
+ScriptFile=@PLYMOUTH_THEME_PATH@/script/script.script
diff --git a/themes/script/script.script b/themes/script/script.script
new file mode 100644 (file)
index 0000000..3db6e15
--- /dev/null
@@ -0,0 +1,45 @@
+index = 0;
+
+while (index<30){
+    mystring = index;
+    if (index<10) mystring = "0" + index;
+    sprites[index] = SpriteNewWithImage("../spinfinity/throbber-" + mystring + ".png");
+    sprites[index].xd = 1 + index;
+    sprites[index].yd = 1 + index;
+    index = index + 1;
+    }
+
+random = 1;
+
+fun update_logo_sprite (sprite){
+    image_width =  ImageGetWidth (sprite.image);
+    image_height = ImageGetHeight(sprite.image);
+    
+    if (sprite.x < 0)
+        sprite.xd = global.random % 5 + 1;
+    if (sprite.y < 0)
+        sprite.yd = global.random % 5 + 1;
+    if ((sprite.x + image_width) > 800)
+        sprite.xd = 0 - (global.random % 5 + 1);
+    if ((sprite.y + image_height) > 600)
+        sprite.yd = 0 - (global.random % 5 + 1);
+
+    global.random = (1 + global.random * 7) % 101;
+    
+    sprite.x = sprite.x + sprite.xd;
+    sprite.y = sprite.y + sprite.yd;
+    
+    SpriteUpdate(sprite);
+    }
+
+
+fun refresh (){
+    index = 0;
+    while (index<30){
+        update_logo_sprite (sprites[index]);
+        index = index + 1;
+        }
+    return;
+    }
+
+PlymouthSetRefreshFunction(refresh);