# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: colin@gibibit.com-20080804171055-36h7yem24erv5fy8
# target_branch: ../../repo/trunk-clean/
# testament_sha1: 1c89c142bccacc692e7e4d96fe51b2cbe5afc77e
# timestamp: 2008-08-04 10:17:09 -0700
# source_branch: http://grub.gibibit.com/bzr/trunk-clean
# base_revision_id: colin@gibibit.com-20080803034658-kcm160bcz0e1rt9f
# 
# Begin patch
=== modified file '.bzrignore'
--- .bzrignore	2008-07-19 21:43:42 +0000
+++ .bzrignore	2008-07-19 21:44:04 +0000
@@ -7,3 +7,5 @@
 ./conf/sparc64-ieee1275.mk
 ./conf/i386-coreboot.mk
 ./build*
+./util/fonttool/build
+./util/fonttool/fonttool.iws

=== modified file 'ChangeLog'
--- ChangeLog	2008-08-02 22:24:34 +0000
+++ ChangeLog	2008-08-03 03:57:46 +0000
@@ -64,7 +64,6 @@
 	(memdisk_mod_SOURCES, memdisk_mod_CFLAGS)
 	(memdisk_mod_LDFLAGS): New variables.
 	* conf/i386-coreboot.rmk: Likewise.
-	* conf/i386-ieee1275.rmk: Likewise.
 
 2008-08-02  Robert Millan  <rmh@aybabtu.com>
 
@@ -197,6 +196,72 @@
 
 	* normal/main.c (get_line): Fix buffer overflow bug.
 
+2008-07-28  Colin D Bennett <colin@gibibit.com>
+
+	High resolution timer support.  Implemented for x86 CPUs using TSC.
+	Extracted generic grub_millisleep() so it's linked in only as needed.
+	This requires a Pentium compatible CPU; if the RDTSC instruction is
+	not supported, then it falls back on the generic grub_get_time_ms()
+	implementation that uses the machine's RTC.
+
+	* conf/i386-efi.rmk: Added new source files to kernel_elf_SOURCES.
+
+	* conf/i386-pc.rmk: Likewise.
+
+	* conf/sparc64-ieee1275.rmk: Likewise.
+
+	* conf/powerpc-ieee1275.rmk: Likewise.
+
+
+	* kern/generic/rtc_get_time_ms.c: New file.
+
+	* kern/generic/millisleep.c: New file.
+
+	* kern/misc.c (grub_millisleep_generic): Removed.
+
+	* commands/sleep.c (grub_interruptible_millisleep): Uses
+	grub_get_time_ms() instead of grub_get_rtc() to stay in sync with
+	grub_millisleep() from kern/generic/millisleep.c.
+
+	* include/grub/i386/tsc.h (grub_get_tsc): New file.  New inline
+	function.
+	(grub_cpu_is_cpuid_supported): New inline function.
+	(grub_cpu_is_tsc_supported): New inline function.
+	(grub_tsc_init): New function prototype.
+	(grub_tsc_get_time_ms): New function prototype.
+
+	* kern/i386/tsc.c (grub_get_time_ms): New file.  New function.
+	(calibrate_tsc): New static function.
+	(grub_tsc_init): New function.
+
+	* include/grub/time.h (grub_millisleep_generic): Removed.
+	(grub_get_time_ms): New function.
+	(grub_install_get_time_ms): New function.
+
+	* kern/time.c (grub_get_time_ms): New function.
+	(grub_install_get_time_ms): New function.
+
+	* kern/i386/efi/init.c (grub_millisleep): Removed.
+	(grub_machine_init): Call grub_tsc_init.
+
+	* kern/i386/linuxbios/init.c (grub_machine_init): Install the RTC
+	get_time_ms() implementation.
+
+	* kern/sparc64/ieee1275/init.c (grub_millisleep): Removed.
+	(ieee1275_get_time_ms): New function.
+	(grub_machine_init): Install get_time_ms() implementation.
+
+	* kern/i386/pc/init.c (grub_machine_init): Call grub_tsc_init().
+	(grub_millisleep): Removed.
+
+	* kern/ieee1275/init.c (grub_millisleep): Removed.
+	(grub_machine_init): Install ieee1275_get_time_ms() implementation.
+	(ieee1275_get_time_ms): New static function.
+	(grub_get_rtc): Now calls ieee1275_get_time_ms(), which does the real
+	work.
+
+	* conf/i386-ieee1275.rmk: Likewise.
+
 2008-07-28  Robert Millan  <rmh@aybabtu.com>
 
 	* partmap/apple.c (GRUB_APPLE_HEADER_MAGIC): New macro.

=== modified file 'Makefile.in'
--- Makefile.in	2008-07-24 13:56:30 +0000
+++ Makefile.in	2008-07-28 02:00:30 +0000
@@ -89,6 +89,39 @@
 YACC = @YACC@
 UNIFONT_HEX = @UNIFONT_HEX@
 
+### Pretty output control ###
+# Set up compiler and linker commands that either is quiet (does not print
+# the command line being executed) or verbose (print the command line).
+_CC := $(CC)
+_TARGET_CC := $(TARGET_CC)
+_STRIP := $(STRIP)
+_GENMODSRC := sh $(srcdir)/genmodsrc.sh
+ifeq ($(V),1)
+ override V_PREFIX :=
+ override CC = $(_CC)
+ override TARGET_CC = $(_CC)
+ override STRIP = $(_STRIP)
+ override GENMODSRC = $(_GENMODSRC)
+ override INFO_GENCMDLIST =
+ override INFO_GENFSLIST =
+ override INFO_GENPARTMAPLIST =
+ override INFO_GEN_FINAL_COMMAND_LIST =
+ override INFO_GEN_FINAL_FS_LIST =
+ override INFO_GEN_FINAL_PARTMAP_LIST =
+else
+ override V_PREFIX := @
+ override CC = @echo "COMPILE         $<"; $(_CC)
+ override TARGET_CC = @echo "COMPILE(TARGET) $<"; $(_TARGET_CC)
+ override STRIP = @echo "STRIP           $@"; $(_STRIP)
+ override GENMODSRC = @echo "GENMODSRC       $@"; $(_GENMODSRC)
+ override INFO_GENCMDLIST = @echo "GENCMDLIST      $@"
+ override INFO_GENFSLIST = @echo "GENFSLIST       $@"
+ override INFO_GENPARTMAPLIST = @echo "GENPARTMAPLIST  $@"
+ override INFO_GEN_FINAL_COMMAND_LIST = @echo "GENCMDLIST[final]  $@"
+ override INFO_GEN_FINAL_FS_LIST = @echo "GENFSLIST[final]   $@"
+ override INFO_GEN_FINAL_PARTMAP_LIST = @echo "GENPARTMAPLIST[final]  $@"
+endif
+
 # Options.
 enable_grub_emu = @enable_grub_emu@
 enable_grub_fstest = @enable_grub_fstest@
@@ -136,13 +169,16 @@
 	  || (rm -f $@; exit 1)
 
 command.lst: $(COMMANDFILES)
-	cat $^ /dev/null | sort > $@
+	$(INFO_GEN_FINAL_COMMAND_LIST)
+	$(V_PREFIX)cat $^ /dev/null | sort > $@
 
 fs.lst: $(FSFILES)
-	cat $^ /dev/null | sort > $@
+	$(INFO_GEN_FINAL_FS_LIST)
+	$(V_PREFIX)cat $^ /dev/null | sort > $@
 
 partmap.lst: $(PARTMAPFILES)
-	cat $^ /dev/null | sort > $@
+	$(INFO_GEN_FINAL_PARTMAP_LIST)
+	$(V_PREFIX)cat $^ /dev/null | sort > $@
 
 ifeq (, $(UNIFONT_HEX))
 else

=== modified file 'commands/i386/pc/vbeinfo.c'
--- commands/i386/pc/vbeinfo.c	2007-07-21 22:32:33 +0000
+++ commands/i386/pc/vbeinfo.c	2008-07-09 14:39:39 +0000
@@ -18,6 +18,7 @@
  */
 
 #include <grub/normal.h>
+#include <grub/term.h>
 #include <grub/dl.h>
 #include <grub/arg.h>
 #include <grub/env.h>
@@ -48,12 +49,22 @@
   grub_err_t err;
   char *modevar;
 
-  grub_printf ("List of compatible video modes:\n");
-
   err = grub_vbe_probe (&controller_info);
   if (err != GRUB_ERR_NONE)
     return err;
 
+  int row = 0;
+
+  grub_printf ("VBE info:   version: %d.%d  OEM software rev: %d.%d\n",
+               controller_info.version >> 8, 
+               controller_info.version & 0xFF,
+               controller_info.oem_software_rev >> 8,
+               controller_info.oem_software_rev & 0xFF);
+  row++;
+  grub_printf ("            total memory: %d KiB\n",
+               (controller_info.total_memory << 16) / 1024);
+  row++;
+
   /* Because the information on video modes is stored in a temporary place,
      it is better to copy it to somewhere safe.  */
   p = video_mode_list = real2pm (controller_info.video_mode_ptr);
@@ -67,6 +78,10 @@
 
   grub_memcpy (saved_video_mode_list, video_mode_list, video_mode_list_size);
   
+  grub_printf ("List of compatible video modes:\n");
+  grub_printf ("Legend: P=Packed pixel, D=Direct color, "
+               "mask/pos=R/G/B/reserved\n"); 
+
   /* Walk through all video modes listed.  */
   for (p = saved_video_mode_list; *p != 0xFFFF; p++)
     {
@@ -103,10 +118,10 @@
       switch (mode_info_tmp.memory_model)
 	{
 	case 0x04:
-	  memory_model = "Packed Pixel";
+	  memory_model = "Packed";
 	  break;
 	case 0x06:
-	  memory_model = "Direct Color";
+	  memory_model = "Direct";
 	  break;
 
 	default:
@@ -116,12 +131,31 @@
       if (! memory_model)
 	continue;
 
-      grub_printf ("0x%03x: %d x %d x %d bpp (%s)\n",
-		   mode,
+      grub_printf ("0x%03x: %4dx%4dx%2d %s", 
+                   mode,
                    mode_info_tmp.x_resolution,
                    mode_info_tmp.y_resolution,
                    mode_info_tmp.bits_per_pixel,
-		   memory_model);
+                   memory_model);
+      if (memory_model[0] == 'D')
+        grub_printf (" mask: %d/%d/%d/%d  pos: %d/%d/%d/%d",
+                     mode_info_tmp.red_mask_size,
+                     mode_info_tmp.green_mask_size,
+                     mode_info_tmp.blue_mask_size,
+                     mode_info_tmp.rsvd_mask_size,
+                     mode_info_tmp.red_field_position,
+                     mode_info_tmp.green_field_position,
+                     mode_info_tmp.blue_field_position,
+                     mode_info_tmp.rsvd_field_position);
+      grub_printf ("\n");
+
+      if (++row >= 25)
+        {
+          grub_printf ("-- More --");
+          grub_getkey ();
+          grub_printf ("\r          \r");
+          row = 0;
+        }
     }
 
   grub_free (saved_video_mode_list);

=== added file 'commands/luagfx.c'
--- commands/luagfx.c	1970-01-01 00:00:00 +0000
+++ commands/luagfx.c	2008-08-04 17:10:55 +0000
@@ -0,0 +1,152 @@
+/* luagfx.c - Test of extending Lua to access GRUB graphics. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/time.h>
+#include <grub/bufio.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/term.h>
+#include <grub/bitmap_scale.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include <grub/luagrub.h>
+
+static grub_err_t
+grub_cmd_luagfx (struct grub_arg_list *state __attribute__ ((unused)),
+                 int argc __attribute__ ((unused)),
+                 char **args __attribute__ ((unused)))
+{
+  /* Load the file into ``buf``.  */
+  const char *filename = "/luagfx.lua";
+  grub_file_t f;
+  grub_errno = GRUB_ERR_NONE;
+  f = grub_file_open (filename);
+  if (! f)
+    return grub_errno;
+  grub_size_t sz = grub_file_size (f);
+  char *buf = grub_malloc (sz);
+  if (! buf)
+    return grub_errno;
+  if ((grub_size_t) grub_file_read (f, buf, sz) != sz)
+    {
+      grub_free (buf);
+      grub_file_close (f);
+      return grub_errno;
+    }
+  grub_file_close (f);
+
+  /* Display info on the file and its loaded contents.  */
+  grub_printf ("Loaded %u bytes from %s.", sz, filename);
+
+  /* Execute some Lua code.  */
+  int err;
+  lua_State *L = lua_open ();
+  luaL_openlibs (L);
+
+  err = luaL_loadstring (L, "print('Hello from a Lua string.')");
+  if (err)
+    {
+      grub_printf ("Lua load string error: %s\n", lua_tostring (L, -1));
+      lua_pop (L, 1);   /* Pop the error message.  */
+      goto end;
+    }
+
+  err = lua_pcall (L, 0, 0, 0);
+  if (err)
+    {
+      grub_printf ("Lua pcall string chunk error: %s\n", lua_tostring (L, -1));
+      lua_pop (L, 1);   /* Pop the error message.  */
+      goto end;
+    }
+
+  err = luaL_loadbuffer (L, buf, sz, filename);
+  grub_free (buf);
+  if (err)
+    {
+      grub_printf ("Lua error: %s\n", lua_tostring (L, -1));
+      lua_pop (L, 1);   /* Pop the error message.  */
+      goto end;
+    }
+
+  err = lua_pcall (L, 0, 0, 0);
+  if (err)
+    {
+      grub_printf ("Error in lua_pcall(): %s\n", lua_tostring (L, -1));
+      goto end;
+    }
+  grub_printf ("Lua chunk executed\n");
+
+  lua_getglobal (L, "main");
+  if (lua_isnoneornil (L, -1))
+    {
+      grub_printf ("Error: symbol 'main' does not exist.\n");
+      goto end;
+    }
+
+  err = lua_pcall (L, 0, 0, 0);
+  if (err)
+    {
+      grub_printf ("Error in lua_pcall(): %s\n", lua_tostring (L, -1));
+      goto end;
+    }
+  grub_printf ("Lua function 'main' executed\n");
+
+  grub_lua_load_grub_packages (L);
+  grub_printf ("GRUB Lua packages loaded\n");
+
+  lua_getglobal (L, "videotest");
+  if (lua_isnoneornil (L, -1))
+    {
+      grub_printf ("Error: symbol 'videotest' does not exist.\n");
+      goto end;
+    }
+
+  err = lua_pcall (L, 0, 0, 0);
+  if (err)
+    {
+      grub_printf ("Error in lua_pcall(): %s\n", lua_tostring (L, -1));
+      goto end;
+    }
+  grub_printf ("Lua function 'videotest' executed\n");
+
+end:
+  lua_close (L);
+  return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT (luagfx)
+{
+  (void) mod;                   /* To stop warning. */
+  grub_register_command ("luagfx",
+                         grub_cmd_luagfx, GRUB_COMMAND_FLAG_BOTH,
+                         "luagfx", "Test of Lua graphics", 0);
+}
+
+GRUB_MOD_FINI (luagfx)
+{
+  grub_unregister_command ("luagfx");
+}

=== added file 'commands/luagfx.lua'
--- commands/luagfx.lua	1970-01-01 00:00:00 +0000
+++ commands/luagfx.lua	2008-08-04 17:10:55 +0000
@@ -0,0 +1,70 @@
+print("This is luagfx.lua, the file chunk.")
+
+function main()
+  print("Hello, world!! This is the function 'main' from Lua!")
+end
+
+function delay(ms)
+  local stop = sys.get_time_ms() + ms
+  while stop - sys.get_time_ms() > 0 do
+  end
+end
+
+function videotest()
+--  video.set_graphics_mode()
+  local seed = 42373
+  local function rand(min,max)
+    seed = seed * 97 + 17 * min * max
+    return seed % (max - min + 1) + min
+  end
+
+  local strings =
+    {
+      "Hello, world!",
+      "GRUB rocks!",
+      "What's up?",
+      "Do the Dew!",
+      "Lua!"
+    }
+  local function new_random_word()
+    local w={}
+    w.speed = rand(5,15)
+    w.x = rand(-200, -100)
+    w.y = rand(40, 440)
+    w.text = strings[rand(1, #strings)]
+    w.color = {r=rand(0,255), g=rand(0,255), b=rand(0,255)}
+    return w
+  end
+
+  local words={}
+  while table.getn(words) < 10 do
+    table.insert(words, new_random_word())
+  end
+  while not input.checkkey() do
+    video.fill_rect({r=255, g=255, b=255}, 0, 0, 640, 480)
+
+    -- Draw the words.
+    for _, w in ipairs(words) do
+      video.draw_string(w.text, "Helvetica Bold 18",
+                        w.color, w.x, w.y)
+    end
+    video.swap_buffers()
+
+    -- Update the word positions and
+    -- refresh words when they reach the edge.
+    for i,w in ipairs(words) do
+      w.x = w.x + w.speed
+      if w.x >= 640 then
+        words[i] = new_random_word()
+      end
+    end
+
+    -- Delay a moment.
+    delay(12)
+  end
+
+  -- Eat the keypress.
+  input.getkey()
+--  video.set_text_mode()
+end
+

=== modified file 'commands/sleep.c'
--- commands/sleep.c	2008-05-16 20:55:29 +0000
+++ commands/sleep.c	2008-07-04 16:55:48 +0000
@@ -43,15 +43,15 @@
   grub_printf ("%d    ", n);
 }
 
-/* Based on grub_millisleep() from kern/misc.c.  */
+/* Based on grub_millisleep() from kern/generic/millisleep.c.  */
 static int
 grub_interruptible_millisleep (grub_uint32_t ms)
 {
-  grub_uint32_t end_at;
-  
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-  
-  while (grub_get_rtc () < end_at)
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  while (grub_get_time_ms () - start < ms)
     if (grub_checkkey () >= 0 &&
 	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC)
       return 1;

=== modified file 'commands/videotest.c'
--- commands/videotest.c	2007-07-21 22:32:33 +0000
+++ commands/videotest.c	2008-07-19 18:25:18 +0000
@@ -17,6 +17,7 @@
  */
 
 #include <grub/machine/memory.h>
+#include <grub/time.h>
 #include <grub/video.h>
 #include <grub/types.h>
 #include <grub/dl.h>
@@ -26,15 +27,38 @@
 #include <grub/mm.h>
 #include <grub/font.h>
 #include <grub/term.h>
-
-static grub_err_t
-grub_cmd_videotest (struct grub_arg_list *state __attribute__ ((unused)),
-                    int argc __attribute__ ((unused)),
-                    char **args __attribute__ ((unused)))
-{
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/machine/vbe.h>   /* for grub_vbe_bios_set_display_start () test */
+/* Option array indices. */
+#define ARGINDEX_TEST_TIME 0
+#define ARGINDEX_DOUBLE_BUF 1
+
+static const struct grub_arg_option arg_options[] = {
+  {"time", 't', 0, "Time to run each test, in seconds.", 0, ARG_TYPE_INT},
+  {"dbuf", 'd', 0, "Use double buffered graphics.", 0, ARG_TYPE_NONE},
+  {0, 0, 0, 0, 0, 0}
+};
+
+#define DEFAULT_TEST_TIME 5
+
+/* Command options -- populated base on command line arguments. */
+struct videotest_options
+{
+  int test_time;
+  int double_buffering;
+};
+
+
+static void
+basic_video_test (struct videotest_options *vt_opts)
+{
+  int mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
   if (grub_video_setup (1024, 768,
                         GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != GRUB_ERR_NONE)
-    return grub_errno;
+    return;
 
   grub_getkey ();
 
@@ -44,7 +68,8 @@
   unsigned int width;
   unsigned int height;
   int i;
-  struct grub_font_glyph glyph;
+  grub_font_t font;
+  struct grub_font_glyph *glyph;
   struct grub_video_render_target *text_layer;
   grub_video_color_t palette[16];
 
@@ -65,8 +90,15 @@
   color = grub_video_map_rgb (0, 255, 255);
   grub_video_fill_rect (color, 100, 100, 100, 100);
 
-  grub_font_get_glyph ('*', &glyph);  
-  grub_video_blit_glyph (&glyph, color, 200 ,0);
+  font = grub_font_get ("Helvetica Bold 14");
+  if (! font)
+    {
+      grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
+      return;
+    }
+
+  glyph = grub_font_get_glyph (font, '*');  
+  grub_video_blit_glyph (glyph, color, 200 ,0);
 
   grub_video_set_viewport (x + 150, y + 150,
                            width - 150 * 2, height - 150 * 2);
@@ -77,18 +109,18 @@
 
   color = grub_video_map_rgb (255, 255, 255);
 
-  grub_font_get_glyph ('A', &glyph);
-  grub_video_blit_glyph (&glyph, color, 16, 16);
-  grub_font_get_glyph ('B', &glyph);
-  grub_video_blit_glyph (&glyph, color, 16 * 2, 16);
+  glyph = grub_font_get_glyph (font, 'A');
+  grub_video_blit_glyph (glyph, color, 16, 16);
+  glyph = grub_font_get_glyph (font, 'B');
+  grub_video_blit_glyph (glyph, color, 16 * 2, 16);
 
-  grub_font_get_glyph ('*', &glyph);
+  glyph = grub_font_get_glyph (font, '*');
 
   for (i = 0; i < 16; i++)
     {
       color = grub_video_map_color (i);
       palette[i] = color;
-      grub_video_blit_glyph (&glyph, color, 16 + i * 16, 32);
+      grub_video_blit_glyph (glyph, color, 16 + i * 16, 32);
     }
 
   grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
@@ -101,30 +133,1076 @@
                                      0, 0, width, height);
     }
 
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  /* Test VBE set display start address. */
+  /* This should scroll the screen, first vertically,
+   * then horizontally.  The horizontal scrolling seems to
+   * only have a resolution of about 16 pixels on my VIA Mini-ITX. */
+  int vbestatus;
+  int vbeok = 0;
+  int vbeerr = 0;
+  for (i = 0; i < 50; i++)
+    {
+      vbestatus = grub_vbe_bios_set_display_start (0, i);
+      if (vbestatus == GRUB_VBE_STATUS_OK)
+        vbeok++;
+      else
+        vbeerr++;
+    }
+
+
+  grub_getkey ();
+
+  for (i = 0; i < 50; i++)
+    {
+      vbestatus = grub_vbe_bios_set_display_start (i, 50);
+      if (vbestatus == GRUB_VBE_STATUS_OK)
+        vbeok++;
+      else
+        vbeerr++;
+    }
+
   grub_getkey ();
 
   grub_video_delete_render_target (text_layer);
-
-  grub_video_restore ();
-
-  for (i = 0; i < 16; i++)
-    grub_printf("color %d: %08x\n", i, palette[i]);
-
-  grub_errno = GRUB_ERR_NONE;
+  grub_video_restore ();
+
+  grub_printf ("VBE set_display_start status: %d\n", vbestatus);
+  grub_printf ("ok: %d\n", vbeok);
+  grub_printf ("errors: %d\n", vbeerr);
+
+  grub_errno = GRUB_ERR_NONE;
+}
+
+
+
+/** 
+ * Simple opaque image blit test. 
+ * Returns the error status in grub_errno.
+ */
+static void
+bitmap_demo (struct videotest_options *vt_opts)
+{
+  int mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (1024, 768, mode_type) != GRUB_ERR_NONE)
+    return;
+
+  grub_video_rect_t view;
+  grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
+                           (unsigned *) &view.width,
+                           (unsigned *) &view.height);
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  const int bm1width = 500, bm1height = 400;
+  struct grub_video_bitmap *bitmap1;
+
+  if (grub_video_bitmap_create (&bitmap1, bm1width, bm1height,
+                                GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+      != GRUB_ERR_NONE)
+    return;
+
+  int offset = 0;
+  int x;
+  int y;
+  grub_uint8_t *data = grub_video_bitmap_get_data (bitmap1);
+  for (y = 0; y < bm1height; y++)
+    {
+      for (x = 0; x < bm1width; x++)
+        {
+          data[offset++] = x ^ y;       /* red */
+          data[offset++] = (x * 3) ^ (y * 3);   /* green */
+          data[offset++] = (x * 2) ^ (y * 2);   /* blue */
+        }
+    }
+
+  /* Blit the entire bitmap in the center of the screen. */
+  grub_video_blit_bitmap (bitmap1,
+                          GRUB_VIDEO_BLIT_REPLACE,
+                          view.x + (view.width - bm1width) / 2,
+                          view.y + (view.height - bm1height) / 2,
+                          0, 0, bm1width, bm1height);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  /* Blit more copies of the bitmap. */
+  /* Upper left. */
+  grub_video_blit_bitmap (bitmap1, GRUB_VIDEO_BLIT_REPLACE,
+                          view.x, view.y, 0, 0, bm1width, bm1height);
+  /* Upper right. */
+  grub_video_blit_bitmap (bitmap1,
+                          GRUB_VIDEO_BLIT_REPLACE,
+                          view.x + view.width - bm1width,
+                          view.y, 0, 0, bm1width, bm1height);
+  /* Lower left. */
+  grub_video_blit_bitmap (bitmap1,
+                          GRUB_VIDEO_BLIT_REPLACE,
+                          view.x,
+                          view.y + view.height - bm1height,
+                          0, 0, bm1width, bm1height);
+  /* Lower right. */
+  grub_video_blit_bitmap (bitmap1,
+                          GRUB_VIDEO_BLIT_REPLACE,
+                          view.x + view.width - bm1width,
+                          view.y + view.height - bm1height,
+                          0, 0, bm1width, bm1height);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  int clearbg = 0;              /* Boolean flag: whether to fill background. */
+  grub_video_color_t bgcolor = grub_video_map_rgb (16, 16, 96);
+
+  /* Animate the image sliding in. End when a key is pressed. */
+  int vscale = 1000;
+  int velocityx = -5000;
+  int velocityy = -8000;
+  int positionx = 100;
+  int positiony = 300;
+
+  grub_uint32_t frame_count = 0;
+  grub_uint32_t start_time = grub_get_time_ms ();
+
+  while (grub_checkkey () == -1)
+    {
+      /* If the time limit option is set, then check if it's exceeded. */
+      if (vt_opts->test_time != 0
+          && grub_get_time_ms () >= start_time + vt_opts->test_time * 1000)
+        break;
+
+      int newx = positionx + velocityx / vscale;
+      int newy = positiony + velocityy / vscale;
+
+      /* Check collision w/ left */
+      if (newx < view.x && velocityx < 0)
+        {
+          velocityx = -velocityx;
+          newx = positionx + velocityx / vscale;
+        }
+      /* Check collision w/ right */
+      if (newx + bm1width > view.x + view.width && velocityx > 0)
+        {
+          velocityx = -velocityx;
+          newx = positionx + velocityx / vscale;
+        }
+      /* Check collision w/ top */
+      if (newy < 0 && velocityy < 0)
+        {
+          velocityy = -velocityy;
+          newy = positiony + velocityy / vscale;
+        }
+      /* Check collision w/ bottom */
+      if (newy + bm1height > view.y + view.height && velocityy > 0)
+        {
+          velocityy = -velocityy;
+          newy = positiony + velocityy / vscale;
+        }
+
+      positionx = newx;
+      positiony = newy;
+
+      if (clearbg)
+        grub_video_fill_rect (bgcolor, view.x, view.y, view.width,
+                              view.height);
+
+      grub_video_blit_bitmap (bitmap1,
+                              GRUB_VIDEO_BLIT_REPLACE,
+                              view.x + positionx,
+                              view.y + positiony, 0, 0, bm1width, bm1height);
+      grub_video_swap_buffers ();
+      frame_count++;
+
+      /* Acceleration due to  gravity... 
+       * note that the y coordinate is increasing downward. */
+      velocityy += vscale / 7;
+    }
+
+  /* Calculate average frame rate. */
+  grub_uint32_t duration = grub_get_time_ms () - start_time;
+  grub_uint32_t fps_x10 = 10 * 1000 * frame_count / duration;
+
+  /* Eat the keystroke. */
+  if (grub_checkkey () != -1)
+    grub_getkey ();
+
+  grub_video_bitmap_destroy (bitmap1);
+  grub_video_restore ();
+
+  grub_printf ("Average frame rate: %d.%d fps\n", fps_x10 / 10, fps_x10 % 10);
+
+  grub_errno = GRUB_ERR_NONE;
+}
+
+
+
+/* Configuration settings for a benchmark run. */
+struct benchmark_config
+{
+  int width;
+  int height;
+  unsigned int mode_type;
+  int use_rgba_bitmaps;
+};
+
+/* Macro to make the benchmark_configs[] declaration more concise. */
+#define MODE_TYPE_RGB(bpp) (GRUB_VIDEO_MODE_TYPE_RGB \
+                            | ((bpp) << GRUB_VIDEO_MODE_TYPE_DEPTH_POS))
+
+/* The video configurations to use for the benchmark. */
+static struct benchmark_config benchmark_configs[] = {
+  {320, 200, MODE_TYPE_RGB (0), 0},
+  {640, 480, MODE_TYPE_RGB (0), 0},
+  {1024, 768, MODE_TYPE_RGB (0), 0},
+  {1024, 768, MODE_TYPE_RGB (0), 1},
+};
+
+#define NUM_BENCHMARK_CONFIGS (sizeof(benchmark_configs) \
+                               / sizeof(benchmark_configs[0]))
+
+struct benchmark_result
+{
+  /* If set to 1, the test was able to run successfully; 
+   * 0 means there was an error. */
+  int test_passed;
+
+  /* Bits per pixel for the video mode used. */
+  int bpp;
+
+  /* All fps are in fps * 10 to achieve one decimal place. */
+  /* Set to 0 to indicate the test could not be run. */
+  grub_int32_t fill_fps;
+  grub_int32_t blit_fps;
+  grub_int32_t blend_fps;
+};
+
+#define BENCHMARK_RESULT_FPS_SCALE 10
+
+static void
+move_rectangle_one_step (int *x, int *y,
+                         int width, int height,
+                         int *vx, int *vy, const grub_video_rect_t * bounds)
+{
+  int newx = *x + *vx;
+  int newy = *y + *vy;
+
+  /* Check collision w/ left */
+  if (newx < bounds->x && *vx < 0)
+    {
+      *vx = -*vx;
+      newx = *x + *vx;
+    }
+  /* Check collision w/ right */
+  if (newx + width > bounds->x + bounds->width && *vx > 0)
+    {
+      *vx = -*vx;
+      newx = *x + *vx;
+    }
+  /* Check collision w/ top */
+  if (newy < 0 && *vy < 0)
+    {
+      *vy = -*vy;
+      newy = *y + *vy;
+    }
+  /* Check collision w/ bottom */
+  if (newy + height > bounds->y + bounds->height && *vy > 0)
+    {
+      *vy = -*vy;
+      newy = *y + *vy;
+    }
+
+  *x = newx;
+  *y = newy;
+}
+
+/**
+ * Run the benchmark test for a particular video mode, which is specified 
+ * by ``*config``.  The results of the test are stored in ``*result``.
+ */
+static void
+do_benchmark (const struct benchmark_config *config,
+              struct benchmark_result *result,
+              struct videotest_options *vt_opts)
+{
+  struct grub_video_mode_info modeinfo;
+
+  result->test_passed = 0;
+  result->fill_fps = 0;
+  result->blit_fps = 0;
+  result->blend_fps = 0;
+  result->bpp = 0;
+
+  int mode_type = config->mode_type;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (config->width, config->height,
+                        mode_type) != GRUB_ERR_NONE)
+    return;
+
+  if (grub_video_get_info (&modeinfo) == GRUB_ERR_NONE)
+    result->bpp = modeinfo.bpp;
+
+  /* Full screen bitmap blit test. */
+
+  grub_video_rect_t view;
+  grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
+                           (unsigned *) &view.width,
+                           (unsigned *) &view.height);
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+
+  /* For measuring timing. */
+  grub_uint32_t frame_count;
+  grub_uint64_t start_time;
+  grub_uint64_t desired_stop_time;
+  grub_uint32_t duration;
+
+
+  /*** FILL TEST ***/
+
+  /* Alternates between 0 and 1 to change the color. */
+  int color_flag = 0;
+  grub_video_color_t fillcolors[2];
+  fillcolors[0] = grub_video_map_rgb (0, 0, 255);
+  fillcolors[1] = grub_video_map_rgb (255, 255, 0);
+
+  frame_count = 0;
+  start_time = grub_get_time_ms ();
+  desired_stop_time = start_time + vt_opts->test_time * 1000;
+
+  while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
+    {
+      grub_video_fill_rect (fillcolors[color_flag],
+                            view.x, view.y, view.width, view.height);
+      grub_video_swap_buffers ();
+      color_flag ^= 1;
+      frame_count++;
+    }
+  if (grub_checkkey () != -1)
+    grub_getkey ();             /* Eat the keypress, if there was one. */
+
+  /* Calculate average frame rate. */
+  duration = grub_get_time_ms () - start_time;
+  if (duration == 0)
+    {
+      result->fill_fps = 0;
+    }
+  else
+    {
+      result->fill_fps =
+        (BENCHMARK_RESULT_FPS_SCALE * 1000
+         * frame_count / duration);
+    }
+
+
+  /*** BLIT TEST ***/
+
+  /* Generate two bitmaps, the same size as the screen. */
+  const int bitmapwidth = view.width, bitmapheight = view.height;
+  struct grub_video_bitmap *bitmap1;
+  struct grub_video_bitmap *bitmap2;
+  enum grub_video_blit_format bitmap_format = config->use_rgba_bitmaps
+    ? GRUB_VIDEO_BLIT_FORMAT_RGBA_8888 : GRUB_VIDEO_BLIT_FORMAT_RGB_888;
+
+  if (grub_video_bitmap_create (&bitmap1, bitmapwidth, bitmapheight,
+                                bitmap_format) != GRUB_ERR_NONE)
+    return;
+
+  if (grub_video_bitmap_create (&bitmap2, bitmapwidth, bitmapheight,
+                                bitmap_format) != GRUB_ERR_NONE)
+    {
+      grub_video_bitmap_destroy (bitmap1);
+      return;
+    }
+
+  int offset;
+  int x;
+  int y;
+  grub_uint8_t *data;
+
+  offset = 0;
+  data = grub_video_bitmap_get_data (bitmap1);
+  for (y = 0; y < bitmapheight; y++)
+    {
+      for (x = 0; x < bitmapwidth; x++)
+        {
+          data[offset++] = x ^ y;       /* red */
+          data[offset++] = (x * 3) ^ (y * 3);   /* green */
+          data[offset++] = (x * 2) ^ (y * 2);   /* blue */
+          if (config->use_rgba_bitmaps)
+            data[offset++] = 255;
+        }
+    }
+
+  offset = 0;
+  data = grub_video_bitmap_get_data (bitmap2);
+  for (y = 0; y < bitmapheight; y++)
+    {
+      for (x = 0; x < bitmapwidth; x++)
+        {
+          data[offset++] = x + y;       /* red */
+          data[offset++] = x * x + y * y;       /* green */
+          data[offset++] = x * x / 4 + y * y / 4;       /* blue */
+          if (config->use_rgba_bitmaps)
+            data[offset++] = 255;
+        }
+    }
+
+
+  /* Now do the blit test, alternating between the two bitmaps. */
+  frame_count = 0;
+  start_time = grub_get_time_ms ();
+  desired_stop_time = start_time + vt_opts->test_time * 1000;
+
+  int cur = 0;                  /* Which bitmap to draw this frame. */
+  while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
+    {
+      struct grub_video_bitmap *current_bitmap = cur == 0 ? bitmap1 : bitmap2;
+      grub_video_blit_bitmap (current_bitmap,
+                              GRUB_VIDEO_BLIT_REPLACE,
+                              view.x, view.y, 0, 0, bitmapwidth,
+                              bitmapheight);
+      grub_video_swap_buffers ();
+      frame_count++;
+      cur ^= 1;
+    }
+  if (grub_checkkey () != -1)
+    grub_getkey ();             /* Eat the keypress, if there was once. */
+
+  /* Calculate average frame rate. */
+  duration = grub_get_time_ms () - start_time;
+  if (duration == 0)
+    {
+      result->blit_fps = 0;
+    }
+  else
+    {
+      result->blit_fps =
+        (BENCHMARK_RESULT_FPS_SCALE * 1000
+         * frame_count / duration);
+    }
+
+  grub_video_bitmap_destroy (bitmap2);
+  grub_video_bitmap_destroy (bitmap1);
+
+
+
+  /*** BLEND TEST ***/
+
+  /* Generate two bitmaps, with alpha translucency. */
+  const int bbw = view.width * 2 / 3;
+  const int bbh = view.height * 2 / 3;
+
+  if (grub_video_bitmap_create (&bitmap1, bbw, bbh,
+                                GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) !=
+      GRUB_ERR_NONE)
+    return;
+
+  if (grub_video_bitmap_create (&bitmap2, bbw, bbh,
+                                GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) !=
+      GRUB_ERR_NONE)
+    {
+      grub_video_bitmap_destroy (bitmap1);
+      return;
+    }
+
+  offset = 0;
+  data = grub_video_bitmap_get_data (bitmap1);
+  for (y = 0; y < bbh; y++)
+    {
+      for (x = 0; x < bbw; x++)
+        {
+          /* Calculate a to be increasing away from the center. */
+          int dx = 256 * (x - bbw / 2) / (bbw / 2);
+          int dy = 256 * (y - bbh / 2) / (bbh / 2);
+          int a = dx * dx + dy * dy;
+          /* range for a = 0 .. 2*(256^2) = 2*2^16 = 2^17 */
+          a >>= 17 - 8;         /* Make range 0..256. */
+          if (a > 255)
+            a = 255;
+
+          data[offset++] = x ^ y;       /* red */
+          data[offset++] = (x * 3) ^ (y * 3);   /* green */
+          data[offset++] = (x * 2) ^ (y * 2);   /* blue */
+          data[offset++] = 255 - a;
+        }
+    }
+
+  offset = 0;
+  data = grub_video_bitmap_get_data (bitmap2);
+  for (y = 0; y < bbh; y++)
+    {
+      for (x = 0; x < bbw; x++)
+        {
+          data[offset++] = x + y;       /* red */
+          data[offset++] = x * x + y * y;       /* green */
+          data[offset++] = x * x / 4 + y * y / 4;       /* blue */
+          data[offset++] = 255;
+        }
+    }
+
+  frame_count = 0;
+  start_time = grub_get_time_ms ();
+  desired_stop_time = start_time + vt_opts->test_time * 1000;
+
+
+  grub_video_color_t bgcolor = grub_video_map_rgb (80, 80, 80);
+
+  /* Bitmap locations. */
+  int b1x = 0;
+  int b1y = 0;
+  int b2x = view.width - bbw;
+  int b2y = 0;
+  /* Bitmap velocities. */
+  int b1vx = 8;
+  int b1vy = 12;
+  int b2vx = -10;
+  int b2vy = 9;
+
+  while (grub_get_time_ms () < desired_stop_time && grub_checkkey () == -1)
+    {
+      move_rectangle_one_step (&b1x, &b1y, bbw, bbh, &b1vx, &b1vy, &view);
+      move_rectangle_one_step (&b2x, &b2y, bbw, bbh, &b2vx, &b2vy, &view);
+      grub_video_fill_rect (bgcolor, view.x, view.y, view.width, view.height);
+      grub_video_blit_bitmap (bitmap2,
+                              GRUB_VIDEO_BLIT_BLEND,
+                              b2x, b2y, 0, 0, bbw, bbh);
+      grub_video_blit_bitmap (bitmap1,
+                              GRUB_VIDEO_BLIT_BLEND,
+                              b1x, b1y, 0, 0, bbw, bbh);
+      grub_video_swap_buffers ();
+      frame_count++;
+      cur ^= 1;
+    }
+  if (grub_checkkey () != -1)
+    grub_getkey ();             /* Eat the keypress, if there was once. */
+
+  /* Calculate average frame rate. */
+  duration = grub_get_time_ms () - start_time;
+  if (duration == 0)
+    {
+      result->blend_fps = 0;
+    }
+  else
+    {
+      result->blend_fps =
+        (BENCHMARK_RESULT_FPS_SCALE * 1000
+         * frame_count / duration);
+    }
+
+  grub_video_bitmap_destroy (bitmap2);
+  grub_video_bitmap_destroy (bitmap1);
+
+  grub_video_restore ();
+  result->test_passed = 1;
+}
+
+/**
+ * Run a benchmark test in a series of video modes.
+ * The results are reported in tabular form.  This will be helpful to
+ * determine how effective various optimizations are.
+ */
+static void
+benchmark_test (struct videotest_options *vt_opts)
+{
+  unsigned int i;
+  struct benchmark_result results[NUM_BENCHMARK_CONFIGS];
+
+  /* Set option default values. */
+  if (vt_opts->test_time == 0)
+    vt_opts->test_time = DEFAULT_TEST_TIME;
+
+  /* Run benchmarks. */
+  for (i = 0; i < NUM_BENCHMARK_CONFIGS; i++)
+    {
+      grub_error_push ();
+      do_benchmark (&benchmark_configs[i], &results[i], vt_opts);
+    }
+
+  grub_print_error ();
+
+  /* Display results. */
+  grub_printf ("Benchmark results (in frames/s):\n");
+  grub_printf ("(W=Width, H=Height, B=Bits per pixel,\n"
+               " T=Mode Type, A=Bitmap Alpha)\n");
+  grub_printf ("   W    H  B T A    FILL    BLIT   BLEND\n");
+  for (i = 0; i < NUM_BENCHMARK_CONFIGS; i++)
+    {
+      struct benchmark_config *c = &benchmark_configs[i];
+      struct benchmark_result *r = &results[i];
+
+      if (r->test_passed)
+        {
+          grub_printf ("%4dx%4d %2d %d %d: %4d.%d  %4d.%d  %4d.%d\n",
+                       c->width, c->height, r->bpp,
+                       c->mode_type & 0x0F,
+                       c->use_rgba_bitmaps,
+                       r->fill_fps / BENCHMARK_RESULT_FPS_SCALE,
+                       r->fill_fps % BENCHMARK_RESULT_FPS_SCALE,
+                       r->blit_fps / BENCHMARK_RESULT_FPS_SCALE,
+                       r->blit_fps % BENCHMARK_RESULT_FPS_SCALE,
+                       r->blend_fps / BENCHMARK_RESULT_FPS_SCALE,
+                       r->blend_fps % BENCHMARK_RESULT_FPS_SCALE);
+        }
+      else
+        {
+          grub_printf ("%4dx%4d %2d %d  Not supported.\n",
+                       c->width, c->height,
+                       ((c->mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
+                        >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS),
+                       c->mode_type & 0x0F);
+        }
+    }
+
+  grub_errno = GRUB_ERR_NONE;
+}
+
+
+/**
+ * Test time functions.
+ */
+static void
+clock_test (struct videotest_options *vt_opts)
+{
+  int mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (640, 480, mode_type) != GRUB_ERR_NONE)
+    return;
+
+  grub_video_rect_t view;
+  grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
+                           (unsigned *) &view.width,
+                           (unsigned *) &view.height);
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  /* Draw a progress bar that animates in sync with time. */
+
+  grub_video_rect_t bar_frame;
+  bar_frame.width = view.width - 2 * view.width / 10;
+  bar_frame.height = view.height / 20;
+  bar_frame.x = view.x + view.width / 10;
+  bar_frame.y = view.y + view.height - bar_frame.height - view.height / 10;
+
+  grub_video_color_t bgcolor = grub_video_map_rgb (50, 50, 50);
+  grub_video_color_t framecolor = grub_video_map_rgb (255, 255, 255);
+  grub_video_color_t barbgcolor = grub_video_map_rgb (0, 0, 128);
+  grub_video_color_t barcolor = grub_video_map_rgb (100, 100, 255);
+
+  grub_uint32_t frame_count;
+  grub_uint64_t start_time;
+  grub_uint64_t barstart;
+  grub_uint32_t barlength = 1000;
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  frame_count = 0;
+  start_time = grub_get_time_ms ();
+  barstart = grub_get_time_ms ();
+
+  while (grub_checkkey () == -1)
+    {
+      grub_uint64_t now;
+      grub_uint32_t bartime;
+      now = grub_get_time_ms ();
+      /* If the time limit option is set, then check if it's exceeded. */
+      if (vt_opts->test_time != 0
+          && now >= start_time + vt_opts->test_time * 1000)
+        break;
+      bartime = now - barstart;
+      if (bartime > barlength)
+        {
+          barstart = grub_get_time_ms ();       /* Start over. */
+          bartime = barlength;
+        }
+
+      /* Clear screen. */
+      grub_video_fill_rect (bgcolor, view.x, view.y, view.width, view.height);
+
+      /* Border. */
+      grub_video_fill_rect (framecolor,
+                            bar_frame.x - 1, bar_frame.y - 1,
+                            bar_frame.width + 2, bar_frame.height + 2);
+
+      /* Bar background. */
+      int barwidth = bar_frame.width * bartime / barlength;
+      grub_video_fill_rect (barbgcolor, bar_frame.x + barwidth,
+                            bar_frame.y, bar_frame.width - barwidth,
+                            bar_frame.height);
+      /* Bar foreground. */
+      grub_video_fill_rect (barcolor, bar_frame.x, bar_frame.y,
+                            barwidth, bar_frame.height);
+      grub_video_swap_buffers ();
+      frame_count++;
+    }
+
+  grub_uint32_t duration = grub_get_time_ms () - start_time;
+  grub_uint32_t fps_x10 = 10 * 1000 * frame_count / duration;
+
+  if (grub_checkkey () != -1)
+    grub_getkey ();             /* Eat the keypress, if there was one. */
+  grub_video_restore ();
+  grub_printf ("Average frame rate: %d.%d fps\n", fps_x10 / 10, fps_x10 % 10);
+}
+
+
+/**
+ * Test double buffering.
+ */
+static void
+doublebuf_test (struct videotest_options *vt_opts)
+{
+  int mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (640, 480, mode_type) != GRUB_ERR_NONE)
+    return;
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  grub_video_color_t red = grub_video_map_rgb (255, 50, 50);
+  grub_video_color_t yellow = grub_video_map_rgb (255, 255, 0);
+  grub_video_color_t green = grub_video_map_rgb (20, 255, 20);
+  grub_video_color_t blue = grub_video_map_rgb (50, 50, 255);
+  grub_video_color_t black = grub_video_map_rgb (0, 0, 0);
+  grub_video_color_t bgcolor = grub_video_map_rgb (255, 255, 255);
+
+  grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
+  grub_video_fill_rect (red, 100, 100, 200, 200);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
+  grub_video_fill_rect (yellow, 120, 120, 200, 200);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
+  grub_video_fill_rect (green, 140, 140, 200, 200);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
+  grub_video_fill_rect (blue, 160, 160, 200, 200);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  grub_video_fill_rect (bgcolor, 0, 0, 640, 480);
+  grub_video_fill_rect (black, 180, 180, 200, 200);
+  grub_video_swap_buffers ();
+  grub_getkey ();
+
+  grub_video_restore ();
+}
+
+
+/**
+ * Test text rendering.
+ */
+static void
+text_test (struct videotest_options *vt_opts)
+{
+  grub_video_color_t color;
+  const char *s;
+  int view_x;
+  int view_y;
+  int view_width;
+  int view_height;
+  int xpos;
+  int ypos;
+  int i;
+  grub_font_t font1;
+  grub_font_t font2;
+  grub_font_t font3;
+
+  int mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (1024, 768, mode_type) != GRUB_ERR_NONE)
+    return;
+
+  grub_video_get_viewport ((unsigned int *) &view_x,
+                           (unsigned int *) &view_y,
+                           (unsigned int *) &view_width,
+                           (unsigned int *) &view_height);
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  if (!(font1 = grub_font_get ("New Century Schoolbook 24"))
+      || !(font2 = grub_font_get ("Helvetica Bold 14"))
+      || !(font3 = grub_font_get ("Helvetica 10")))
+    {
+      grub_video_restore ();
+      grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
+      return;
+    }
+
+  color = grub_video_map_rgb (0, 0, 0);
+  grub_video_fill_rect (color, 0, 0, view_width, view_height);
+
+  color = grub_video_map_rgb (255, 0, 0);
+  grub_video_fill_rect (color, 0, 0, 100, 100);
+
+  color = grub_video_map_rgb (0, 255, 255);
+  grub_video_fill_rect (color, 100, 100, 100, 100);
+
+  color = grub_video_map_rgb (255, 255, 255);
+
+  xpos = 10;
+  ypos = 30;
+  s = "Hello, World!";
+  for (i = 0; i < 40; i++)
+    {
+      if (xpos + grub_font_get_string_width (font1, s) >= view_width)
+        {
+          /* The string will wrap; go to the beginning of the next line. */
+          xpos = 10;
+          ypos += (grub_font_get_descent (font1) 
+                   + grub_font_get_ascent (font1));
+        }
+      grub_video_draw_string ("Hello, World!",
+                              font1, grub_video_map_rgb (255, 255, 0), 
+                              view_x + xpos, view_y + ypos);
+
+      xpos += grub_font_get_string_width (font1, s);
+    }
+
+  xpos = 300;
+  ypos = 450;
+  grub_video_draw_string (grub_font_get_name (font1),
+                          font1, grub_video_map_rgb (255, 255, 255),
+                          view_x + xpos, view_y + ypos);
+  ypos += grub_font_get_descent (font1) + grub_font_get_ascent (font2) + 2;
+  grub_video_draw_string (grub_font_get_name (font2),
+                          font2, grub_video_map_rgb (255, 255, 255),
+                          view_x + xpos, view_y + ypos);
+  ypos += grub_font_get_descent (font2) + grub_font_get_ascent (font3) + 2;
+  grub_video_draw_string (grub_font_get_name (font3),
+                          font3, grub_video_map_rgb (255, 255, 255),
+                          view_x + xpos, view_y + ypos);
+
+  grub_video_swap_buffers ();
+  grub_getkey ();
+  grub_video_restore ();
+  grub_errno = GRUB_ERR_NONE;
+}
+
+
+/**
+ * Test bitmap scaling.
+ */
+static void
+scale_test (struct videotest_options *vt_opts)
+{
+  int mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
+  if (vt_opts->double_buffering)
+    mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  if (grub_video_setup (1024, 768, mode_type) != GRUB_ERR_NONE)
+    return;
+
+  grub_errno = GRUB_ERR_NONE;
+  grub_video_rect_t view;
+  grub_video_get_viewport ((unsigned *) &view.x, (unsigned *) &view.y,
+                           (unsigned *) &view.width,
+                           (unsigned *) &view.height);
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  grub_font_t font;
+  if (!(font = grub_font_get ("Helvetica 10")))
+    {
+      grub_video_restore ();
+      grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
+      return;
+    }
+
+  grub_video_color_t color;
+
+  int text_y = 0;
+  int text_height = 25;
+
+  color = grub_video_map_rgb (44, 44, 200);
+  grub_video_fill_rect (color, view.x, view.y, view.width, view.height);
+  color = grub_video_map_rgb (255, 255, 255);
+
+  grub_video_draw_string ("Loading image", 
+                          font, color, 10, text_y += text_height);
+
+  enum grub_video_bitmap_scale_method scale_method = 
+    GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST;
+  const char *bitmap_name = "/boot/images/wallpaper.tga";
+  struct grub_video_bitmap *bitmap;
+  grub_video_bitmap_load (&bitmap, bitmap_name);
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_video_draw_string ("Error loading bitmap", 
+                              font, color, 10, text_y += text_height);
+    }
+  else 
+    {
+      grub_video_draw_string ("Original image", 
+                              font, color, 10, text_y += text_height);
+      grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND,
+                              400, text_y - 10,
+                              0, 0, grub_video_bitmap_get_width (bitmap),
+                              grub_video_bitmap_get_height (bitmap));
+
+      struct grub_video_bitmap *bitmap2;
+      if (grub_video_bitmap_create_scaled (&bitmap2, 40, 40,
+                                              bitmap,
+                                              scale_method)
+          != GRUB_ERR_NONE)
+        {
+          grub_video_draw_string ("Error scaling down bitmap", 
+                                  font, color, 10, text_y += text_height);
+        }
+      else
+        {
+          grub_video_draw_string ("Scaled down version", 
+                                  font, color, 10, text_y += text_height);
+          grub_video_blit_bitmap (bitmap2, GRUB_VIDEO_BLIT_BLEND,
+                                  400, text_y + 100,
+                                  0, 0, grub_video_bitmap_get_width (bitmap2),
+                                  grub_video_bitmap_get_height (bitmap2));
+          grub_video_bitmap_destroy (bitmap2);
+        }
+
+      struct grub_video_bitmap *bitmap3;
+      if (grub_video_bitmap_create_scaled (&bitmap3, 500, 300, bitmap,
+                                           scale_method)
+          != GRUB_ERR_NONE)
+        {
+          grub_video_draw_string ("Error scaling up bitmap", 
+                                  font, color, 10, text_y += text_height);
+        }
+      else
+        {
+          grub_video_draw_string ("Scaled up version", 
+                                  font, color, 10, text_y += text_height);
+          grub_video_blit_bitmap (bitmap3, GRUB_VIDEO_BLIT_BLEND,
+                                  400, text_y + 50,
+                                  0, 0, grub_video_bitmap_get_width (bitmap3),
+                                  grub_video_bitmap_get_height (bitmap3));
+          grub_video_bitmap_destroy (bitmap3);
+        }
+    }
+
+  grub_video_swap_buffers ();
+  grub_getkey ();
+  grub_video_bitmap_destroy (bitmap);
+  grub_video_restore ();
+}
+
+
+/** Print a list of the available tests. */
+static void list_tests (void);
+
+/**
+ * Video test command.  Takes an argument specifying the test to run.
+ */
+static grub_err_t
+grub_cmd_videotest (struct grub_arg_list *state, int argc, char **args)
+{
+  int i;
+  struct videotest_options vt_opts;
+  /* Pointer to the test function. */
+  void (*test_func) (struct videotest_options *) = NULL;
+
+  vt_opts.test_time =
+    state[ARGINDEX_TEST_TIME].set
+    ? grub_strtoul (state[ARGINDEX_TEST_TIME].arg, 0, 0) : 0;
+  vt_opts.double_buffering = state[ARGINDEX_DOUBLE_BUF].set;
+
+  /* Parse command line arguments to determine the test to run. */
+  for (i = 0; i < argc; i++)
+    {
+      char *arg = args[i];
+      if (grub_strcmp (arg, "list") == 0)
+        {
+          list_tests ();
+          return GRUB_ERR_NONE;
+        }
+      else if (grub_strcmp (arg, "basic") == 0)
+        {
+          test_func = basic_video_test;
+        }
+      else if (grub_strcmp (arg, "bench") == 0)
+        {
+          test_func = benchmark_test;
+        }
+      else if (grub_strcmp (arg, "bitmaps") == 0)
+        {
+          test_func = bitmap_demo;
+        }
+      else if (grub_strcmp (arg, "clock") == 0)
+        {
+          test_func = clock_test;
+        }
+      else if (grub_strcmp (arg, "doublebuf") == 0)
+        {
+          test_func = doublebuf_test;
+        }
+      else if (grub_strcmp (arg, "text") == 0)
+        {
+          test_func = text_test;
+        }
+      else if (grub_strcmp (arg, "scale") == 0)
+        {
+          test_func = scale_test;
+        }
+      else
+        {
+          grub_printf ("Error: Unknown test `%s'\n", arg);
+          grub_errno = GRUB_ERR_BAD_ARGUMENT;
+          return grub_errno;
+        }
+    }
+
+  if (test_func == NULL)
+    {
+      grub_printf ("Usage: videotest TESTNAME    Run a test.\n");
+      grub_printf ("       videotest list        List available tests.\n");
+      grub_printf ("\n");
+      list_tests ();
+    }
+  else
+    {
+      test_func (&vt_opts);
+    }
+
   return grub_errno;
 }
 
-GRUB_MOD_INIT(videotest)
+static void
+list_tests (void)
+{
+  grub_printf ("Available tests\n");
+  grub_printf ("===============\n");
+  grub_printf ("basic       Basic video test with filled rectangles,\n");
+  grub_printf ("            offscreen rendering targets, some text.\n");
+  grub_printf ("bench       Run a performance benchmark.\n");
+  grub_printf ("bitmaps     Test generating and blitting bitmaps.\n");
+  grub_printf ("clock       Test time functions w/ animated progress bar.\n");
+  grub_printf ("doublebuf   Test double buffering.\n");
+  grub_printf ("text        Test text rendering.\n");
+  grub_printf ("scale       Test image scaling.\n");
+  grub_printf ("\n");
+}
+
+
+GRUB_MOD_INIT (videotest)
 {
   grub_register_command ("videotest",
                          grub_cmd_videotest,
                          GRUB_COMMAND_FLAG_BOTH,
-                         "videotest",
-                         "Test video subsystem",
-                         0);
+                         "videotest TEST",
+                         "Run the specified video subsystem test.",
+                         arg_options);
 }
 
-GRUB_MOD_FINI(videotest)
+GRUB_MOD_FINI (videotest)
 {
   grub_unregister_command ("videotest");
 }

=== modified file 'conf/common.rmk'
--- conf/common.rmk	2008-08-01 03:06:55 +0000
+++ conf/common.rmk	2008-08-04 17:10:55 +0000
@@ -274,6 +274,7 @@
 	cmp.mod cat.mod help.mod font.mod search.mod		\
 	loopback.mod fs_uuid.mod configfile.mod echo.mod	\
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
+	gfxmenu.mod                                             \
 	read.mod sleep.mod loadenv.mod crc.mod
 
 # For hello.mod.
@@ -281,6 +282,16 @@
 hello_mod_CFLAGS = $(COMMON_CFLAGS)
 hello_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For gfxmenu.mod.
+gfxmenu_mod_SOURCES = \
+	gfxmenu/gfxmenu.c \
+	gfxmenu/model.c \
+	gfxmenu/view.c \
+	gfxmenu/widget-box.c \
+	gfxmenu/stringutil.c
+gfxmenu_mod_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/lua
+gfxmenu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For boot.mod.
 boot_mod_SOURCES = commands/boot.c
 boot_mod_CFLAGS = $(COMMON_CFLAGS)
@@ -317,7 +328,7 @@
 help_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For font.mod.
-font_mod_SOURCES = font/manager.c
+font_mod_SOURCES = font/font_cmd.c font/font.c font/loader.c
 font_mod_CFLAGS = $(COMMON_CFLAGS)
 font_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
@@ -382,7 +393,9 @@
 crc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Misc.
-pkglib_MODULES += gzio.mod bufio.mod elf.mod
+pkglib_MODULES += gzio.mod bufio.mod elf.mod \
+	lua.mod luacmd.mod \
+	luagfx.mod luagrub.mod
 
 # For elf.mod.
 elf_mod_SOURCES = kern/elf.c
@@ -398,3 +411,32 @@
 bufio_mod_SOURCES = io/bufio.c
 bufio_mod_CFLAGS = $(COMMON_CFLAGS)
 bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For lua.mod.
+lua_mod_SOURCES = lua/lapi.c lua/lcode.c lua/ldebug.c lua/ldo.c lua/ldump.c \
+	lua/lfunc.c lua/lgc.c lua/llex.c lua/lmem.c lua/lobject.c \
+	lua/lopcodes.c lua/lparser.c lua/lstate.c lua/lstring.c \
+	lua/ltable.c lua/ltm.c lua/lundump.c lua/lvm.c lua/lzio.c \
+	lua/lauxlib.c lua/linit.c lua/lbaselib.c lua/ldblib.c lua/ltablib.c \
+	lua/lstrlib.c
+lua_mod_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/lua -DUSE_GRUB_LIB
+lua_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For luacmd.mod.
+luacmd_mod_SOURCES = lua/luacmd.c lua/lua.c
+# Omitted lua/liolib.c and lua/loslib.c because they need to be ported to
+# use the GRUB library.
+luacmd_mod_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/lua \
+		    -DUSE_GRUB_LIB -DGRUB_COMMAND
+luacmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For luagfx.mod.
+luagfx_mod_SOURCES = commands/luagfx.c
+luagfx_mod_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/lua
+luagfx_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For luagrub.mod.
+luagrub_mod_SOURCES = lib/luagrub.c
+luagrub_mod_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/lua
+luagrub_mod_LDFLAGS = $(COMMON_LDFLAGS)
+

=== modified file 'conf/i386-coreboot.rmk'
--- conf/i386-coreboot.rmk	2008-08-02 11:17:44 +0000
+++ conf/i386-coreboot.rmk	2008-08-03 03:57:46 +0000
@@ -16,6 +16,7 @@
 	kern/main.c kern/device.c \
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
+	kern/time.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
 	term/i386/pc/console.c \

=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-efi.rmk	2008-07-28 16:26:46 +0000
@@ -84,7 +84,10 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
-	term/efi/console.c disk/efi/efidisk.c
+	term/efi/console.c disk/efi/efidisk.c \
+	kern/i386/tsc.c \
+	kern/generic/rtc_get_time_ms.c \
+	kern/generic/millisleep.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \

=== modified file 'conf/i386-ieee1275.rmk'
--- conf/i386-ieee1275.rmk	2008-08-02 11:17:44 +0000
+++ conf/i386-ieee1275.rmk	2008-08-03 03:57:46 +0000
@@ -19,6 +19,7 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/i386/dl.c kern/parser.c kern/partition.c \
 	kern/env.c \
+	kern/generic/millisleep.c \
 	kern/ieee1275/ieee1275.c \
 	term/ieee1275/ofconsole.c term/i386/pc/at_keyboard.c \
 	disk/ieee1275/ofdisk.c \

=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk	2008-07-27 12:51:30 +0000
+++ conf/i386-pc.rmk	2008-07-28 17:02:56 +0000
@@ -42,13 +42,19 @@
 kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
+	kern/time.c \
 	kern/i386/dl.c kern/i386/pc/init.c kern/parser.c kern/partition.c \
+	kern/i386/tsc.c \
+	kern/generic/rtc_get_time_ms.c \
+	kern/generic/millisleep.c \
 	kern/env.c \
+	kern/menu_viewer.c \
 	term/i386/pc/console.c \
 	symlist.c
 kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
 	partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
+	menu_viewer.h \
 	machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \
 	machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h
 kernel_img_CFLAGS = $(COMMON_CFLAGS)
@@ -246,7 +252,7 @@
 play_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For video.mod.
-video_mod_SOURCES = video/video.c
+video_mod_SOURCES = video/video.c video/setmode.c
 video_mod_CFLAGS = $(COMMON_CFLAGS)
 video_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
@@ -261,7 +267,10 @@
 videotest_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For bitmap.mod
-bitmap_mod_SOURCES = video/bitmap.c
+bitmap_mod_SOURCES = video/bitmap.c \
+                     video/bitmap_scale_nn.c \
+                     video/bitmap_scale_bilinear.c \
+                     video/bitmap_scale.c
 bitmap_mod_CFLAGS = $(COMMON_CFLAGS)
 bitmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
 

=== modified file 'conf/powerpc-ieee1275.rmk'
--- conf/powerpc-ieee1275.rmk	2008-08-02 11:17:44 +0000
+++ conf/powerpc-ieee1275.rmk	2008-08-03 03:57:46 +0000
@@ -85,6 +85,7 @@
 	kern/ieee1275/init.c term/ieee1275/ofconsole.c 		\
 	kern/ieee1275/openfw.c disk/ieee1275/ofdisk.c 		\
 	kern/parser.c kern/partition.c kern/env.c kern/powerpc/dl.c 	\
+	kern/generic/millisleep.c                                       \
 	symlist.c kern/powerpc/cache.S
 kernel_elf_HEADERS = grub/powerpc/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)

=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk	2008-06-19 00:04:59 +0000
+++ conf/sparc64-ieee1275.rmk	2008-07-03 14:16:34 +0000
@@ -73,6 +73,7 @@
 	kern/rescue.c kern/term.c term/ieee1275/ofconsole.c \
 	kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \
 	kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \
+	kern/generic/millisleep.c kern/generic/get_time_ms.c \
 	kern/sparc64/cache.S kern/parser.c
 kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h
 kernel_elf_CFLAGS = $(COMMON_CFLAGS)
@@ -195,7 +196,7 @@
 cat_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For font.mod.
-font_mod_SOURCES = font/manager.c
+font_mod_SOURCES = font/font_cmd.c font/font.c font/loader.c
 font_mod_CFLAGS = $(COMMON_CFLAGS)
 font_mod_LDFLAGS = $(COMMON_LDFLAGS)
 

=== modified file 'conf/x86_64-efi.rmk'
--- conf/x86_64-efi.rmk	2008-07-27 12:51:30 +0000
+++ conf/x86_64-efi.rmk	2008-07-28 16:23:46 +0000
@@ -87,6 +87,7 @@
 	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
 	kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
 	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
+	kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c \
 	term/efi/console.c disk/efi/efidisk.c
 kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
 	env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \

=== modified file 'config.h.in'
--- config.h.in	2008-07-13 00:55:15 +0000
+++ config.h.in	2008-07-19 21:46:40 +0000
@@ -113,10 +113,37 @@
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
 /* Enable GNU extensions on systems that have them.  */
 #ifndef _GNU_SOURCE
 # undef _GNU_SOURCE
 #endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
 
-/* Define for large files, on AIX-style hosts. */
-#undef _LARGE_FILES

=== added file 'font/font.c'
--- font/font.c	1970-01-01 00:00:00 +0000
+++ font/font.c	2008-07-03 14:12:08 +0000
@@ -0,0 +1,92 @@
+/* font.c - Font functions. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/font_internal.h>
+
+grub_font_t
+grub_font_get (const char *font_name)
+{
+  struct font_node *node;
+
+  for (node = grub_font_list; node; node = node->next)
+    {
+      grub_font_t font = node->value;
+      if (grub_strcmp (font->name, font_name) == 0)
+        return font;
+    }
+
+  /* If no font by that name is found, return the first font in the list
+   * as a fallback. */
+  return grub_font_list->value;
+}
+
+const char *
+grub_font_get_name (grub_font_t font)
+{
+  return font->name;
+}
+
+int
+grub_font_get_max_char_width (grub_font_t font)
+{
+  return font->max_char_width;
+}
+
+int
+grub_font_get_max_char_height (grub_font_t font)
+{
+  return font->max_char_height;
+}
+
+int
+grub_font_get_ascent (grub_font_t font)
+{
+  return font->ascent;
+}
+
+int
+grub_font_get_descent (grub_font_t font)
+{
+  return font->descent;
+}
+
+int
+grub_font_get_string_width (grub_font_t font, const char *str)
+{
+  int i;
+  int width;
+  struct grub_font_glyph *glyph;
+  grub_size_t len;
+
+  len = grub_strlen (str);
+
+  for (i = 0, width = 0; i < len; i++)
+    {
+      glyph = grub_font_get_glyph (font, str[i]);
+      width += glyph->device_width;
+    }
+
+  return width;
+}

=== added file 'font/font_cmd.c'
--- font/font_cmd.c	1970-01-01 00:00:00 +0000
+++ font/font_cmd.c	2008-07-03 14:12:08 +0000
@@ -0,0 +1,75 @@
+/* font_cmd.c - Font command definition. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2005,2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/font_internal.h>
+
+static grub_err_t
+loadfont_command (struct grub_arg_list *state __attribute__ ((unused)),
+	      int argc,
+	      char **args)
+{
+  if (argc == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
+
+  while (argc--)
+    if (grub_font_load (*args++) != 0)
+      return GRUB_ERR_BAD_FONT;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+lsfonts_command (struct grub_arg_list *state __attribute__ ((unused)),
+                 int argc __attribute__ ((unused)),
+                 char **args __attribute__ ((unused)))
+{
+  struct font_node *node;
+
+  grub_printf ("Loaded fonts:\n");
+  for (node = grub_font_list; node; node = node->next)
+    {
+      grub_font_t font = node->value;
+      grub_printf ("%s\n", font->name);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(font_manager)
+{
+  grub_font_loader_init ();
+
+  grub_register_command ("loadfont", loadfont_command, GRUB_COMMAND_FLAG_BOTH,
+			 "loadfont FILE...",
+			 "Specify one or more font files to load.", 0);
+
+  grub_register_command ("lsfonts", lsfonts_command, GRUB_COMMAND_FLAG_BOTH,
+			 "lsfonts",
+			 "List the loaded fonts.", 0);
+}
+
+GRUB_MOD_FINI(font_manager)
+{
+  /* Should this free fonts, unknown_glyph, etc.?  Freeing fonts could 
+   * be a Bad Thing if there are still references to any of them. */
+
+  grub_unregister_command ("loadfont");
+}
+

=== added file 'font/loader.c'
--- font/loader.c	1970-01-01 00:00:00 +0000
+++ font/loader.c	2008-07-29 14:51:29 +0000
@@ -0,0 +1,689 @@
+/* loader.c - Functions to handle loading fonts and glyphs from files. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/file.h>
+#include <grub/bufio.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/font_internal.h>
+
+/* Definition of font registry. */
+struct font_node *grub_font_list;
+
+static int register_font (grub_font_t font);
+static void free_font (grub_font_t font);
+static void remove_font (grub_font_t font);
+
+struct font_file_section
+{
+  grub_file_t file;             /* The file this section is in. */
+  char name[4];                 /* FOURCC name of the section. */
+  grub_uint32_t length;         /* Length of the section contents. */
+  int eof;                      /* Set by open_section() on EOF. */
+};
+
+/* Font file format constants. */
+static const char pff2_magic[4] = { 'P', 'F', 'F', '2' };
+static const char section_names_file[4] = { 'F', 'I', 'L', 'E' };
+static const char section_names_font_name[4] = { 'N', 'A', 'M', 'E' };
+static const char section_names_max_char_width[4] = { 'M', 'A', 'X', 'W' };
+static const char section_names_max_char_height[4] = { 'M', 'A', 'X', 'H' };
+static const char section_names_ascent[4] = { 'A', 'S', 'C', 'E' };
+static const char section_names_descent[4] = { 'D', 'E', 'S', 'C' };
+static const char section_names_char_index[4] = { 'C', 'H', 'I', 'X' };
+static const char section_names_data[4] = { 'D', 'A', 'T', 'A' };
+
+/* Replace unknown glyphs with a rounded question mark.  */
+static grub_uint8_t unknown_glyph_bitmap[] =
+{
+  /*       76543210 */
+  0x7C, /*  ooooo   */
+  0x82, /* o     o  */
+  0xBA, /* o ooo o  */
+  0xAA, /* o o o o  */
+  0xAA, /* o o o o  */
+  0x8A, /* o   o o  */
+  0x9A, /* o  oo o  */
+  0x92, /* o  o  o  */
+  0x92, /* o  o  o  */
+  0x92, /* o  o  o  */
+  0x92, /* o  o  o  */
+  0x82, /* o     o  */
+  0x92, /* o  o  o  */
+  0x82, /* o     o  */
+  0x7C, /*  ooooo   */
+  0x00  /*          */
+};
+
+static struct grub_font_glyph *unknown_glyph;
+
+void
+grub_font_loader_init (void)
+{
+  unknown_glyph = grub_malloc(sizeof(struct grub_font_glyph)
+                              + sizeof(unknown_glyph_bitmap));
+  if (! unknown_glyph)
+    return;
+
+  unknown_glyph->width = 8;
+  unknown_glyph->height = 16;
+  unknown_glyph->offset_x = 0;
+  unknown_glyph->offset_y = 0;
+  unknown_glyph->device_width = 8;
+  grub_memcpy(unknown_glyph->bitmap,
+              unknown_glyph_bitmap, sizeof(unknown_glyph_bitmap));
+}
+
+/*
+   Open the next section in the file.
+
+   On success, the section name is stored in section->name and the length in
+   section->length, and 0 is returned.  On failure, 1 is returned and
+   grub_errno is set approriately with an error message.
+
+   If 1 is returned due to being at the end of the file, then section->eof is
+   set to 1; otherwise, section->eof is set to 0.
+ */
+static int
+open_section (grub_file_t file, struct font_file_section *section)
+{
+  grub_ssize_t retval;
+  grub_uint32_t raw_length;
+
+  section->file = file;
+  section->eof = 0;
+
+  /* Read the FOURCC section name. */
+  retval = grub_file_read (file, section->name, 4);
+  if (retval >= 0 && retval < 4)
+    {
+      section->eof = 1;
+      return 1;                 /* EOF encountered. */
+    }
+  else if (retval < 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font format error: can't read section name");
+      return 1;                 /* Read error. */
+    }
+
+  /* Read the big-endian 32-bit section length. */
+  retval = grub_file_read (file, (char *) &raw_length, 4);
+  if (retval >= 0 && retval < 4)
+    {
+      section->eof = 1;
+      return 1;                 /* EOF encountered. */
+    }
+  else if (retval < 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font format error: can't read section length");
+      return 1;                 /* Read error. */
+    }
+
+  /* Convert byte-order and store in *length. */
+  section->length = grub_be_to_cpu32 (raw_length);
+
+  return 0;
+}
+
+/* Size in bytes of each character index (CHIX section)
+   entry in the font file. */
+#define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4)
+
+/*
+   Load the character index (CHIX) section contents from the font file.  This
+   presumes that the position of FILE is positioned immediately after the
+   section length for the CHIX section (i.e., at the start of the section
+   contents).  Returns 0 upon success, nonzero for failure (in which case
+   grub_errno is set appropriately).
+ */
+static int
+load_font_index (grub_file_t file, grub_uint32_t sect_length, struct
+                 grub_font *font)
+{
+  unsigned i;
+
+#if FONT_DEBUG >= 2
+  grub_printf("load_font_index(sect_length=%d)\n", sect_length);
+#endif
+
+  /* Sanity check: ensure section length is divisible by the entry size.  */
+  if (sect_length % FONT_CHAR_INDEX_ENTRY_SIZE != 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font file format error: character index length %d "
+                  "is not a multiple of the entry size %d",
+                  sect_length, FONT_CHAR_INDEX_ENTRY_SIZE);
+      return 1;                 /* Invalid index section length. */
+    }
+
+  /* Calculate the number of characters. */
+  font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE;
+
+  /* Allocate the character index array. */
+  font->char_index = grub_malloc (font->num_chars
+                                  * sizeof (struct char_index_entry));
+  if (!font->char_index)
+    return 1;                   /* Error allocating memory. */
+
+#if FONT_DEBUG >= 2
+  grub_printf("num_chars=%d)\n", font->num_chars);
+#endif
+
+  /* Load the character index data from the file. */
+  for (i = 0; i < font->num_chars; i++)
+    {
+      struct char_index_entry *entry = &font->char_index[i];
+
+      /* Read code point value; convert to native byte order. */
+      if (grub_file_read (file, (char *) &entry->code, 4) != 4)
+        return 1;
+      entry->code = grub_be_to_cpu32 (entry->code);
+
+      /* Read storage flags byte. */
+      if (grub_file_read (file, (char *) &entry->storage_flags, 1) != 1)
+        return 1;
+
+      /* Read glyph data offset; convert to native byte order. */
+      if (grub_file_read (file, (char *) &entry->offset, 4) != 4)
+        return 1;
+      entry->offset = grub_be_to_cpu32 (entry->offset);
+
+      /* No glyph loaded.  Will be loaded on demand and cached thereafter. */
+      entry->glyph = 0;
+
+#if FONT_DEBUG >= 5
+      if (i < 10)  /* Print the 1st 10 characters. */
+        grub_printf("c=%d o=%d\n", entry->code, entry->offset);
+#endif
+    }
+
+  return 0;                     /* Index loaded OK. */
+}
+
+/*
+   Read the contents of the specified section as a string, which is
+   allocated on the heap.  Returns 0 if there is an error.
+ */
+static char *
+read_section_as_string (struct font_file_section *section)
+{
+  char *str;
+  grub_ssize_t ret;
+
+  str = grub_malloc (section->length + 1);
+  if (!str)
+    return 0;
+
+  ret = grub_file_read (section->file, str, section->length);
+  if (ret < 0 || ret != (grub_ssize_t) section->length)
+    {
+      grub_free (str);
+      return 0;
+    }
+
+  str[section->length] = '\0';
+  return str;
+}
+
+/*
+   Read the contents of the current section as a 16-bit integer value,
+   which is stored into *VALUE.  Returns 0 upon success, nonzero upon failure.
+ */
+static int
+read_section_as_short (struct font_file_section *section, grub_int16_t *value)
+{
+  grub_uint16_t raw_value;
+
+  if (section->length != 2)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font file format error: section %c%c%c%c length "
+                  "is %d but should be 2",
+                  section->name[0], section->name[1],
+                  section->name[2], section->name[3],
+                  section->length);
+      return 1;   /* An error occurred. */
+    }
+  if (grub_file_read (section->file, (char *) &raw_value, 2) != 2)
+    return 1;   /* An error occurred. */
+
+  *value = grub_be_to_cpu16 (raw_value);
+  return 0;   /* Successfully read the value. */
+}
+
+/*
+   Load a font and add it to the beginning of the global font list.
+   Returns 0 upon success, nonzero upon failure.
+ */
+int
+grub_font_load (const char *filename)
+{
+  grub_file_t file = 0;
+  struct font_file_section section;
+  char magic[4];
+  grub_font_t font = 0;
+
+#if FONT_DEBUG >= 1
+  grub_printf("add_font(%s)\n", filename);
+#endif
+
+  file = grub_buffile_open (filename, 1024);
+  if (!file)
+    goto fail;
+
+#if FONT_DEBUG >= 3
+  grub_printf("file opened\n");
+#endif
+
+  /* Read the FILE section.  It indicates the file format. */
+  if (open_section (file, &section) != 0)
+    goto fail;
+
+#if FONT_DEBUG >= 3
+  grub_printf("opened FILE section\n");
+#endif
+  if (grub_memcmp (section.name, section_names_file, 4) != 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font file format error: 1st section must be FILE");
+      goto fail;
+    }
+
+#if FONT_DEBUG >= 3
+  grub_printf("section name ok\n");
+#endif
+  if (section.length != 4)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Font file format error (file type ID length is %d "
+                  "but should be 4)", section.length);
+      goto fail;
+    }
+
+#if FONT_DEBUG >= 3
+  grub_printf("section length ok\n");
+#endif
+  /* Check the file format type code. */
+  if (grub_file_read (file, magic, 4) != 4)
+    goto fail;
+
+#if FONT_DEBUG >= 3
+  grub_printf("read magic ok\n");
+#endif
+
+  if (grub_memcmp (magic, pff2_magic, 4) != 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT, "Invalid font magic %x %x %x %x",
+                  magic[0], magic[1], magic[2], magic[3]);
+      goto fail;
+    }
+
+#if FONT_DEBUG >= 3
+  grub_printf("compare magic ok\n");
+#endif
+
+  /* Allocate the font object. */
+  font = (grub_font_t) grub_malloc (sizeof (struct grub_font));
+  if (!font)
+    goto fail;
+
+  font->file = file;
+  font->name = 0;
+  font->ascent = 0;
+  font->descent = 0;
+  font->max_char_width = 0;
+  font->max_char_height = 0;
+  font->num_chars = 0;
+  font->char_index = 0;
+
+#if FONT_DEBUG >= 3
+  grub_printf("allocate font ok; loading font info\n");
+#endif
+
+  /* Load the font information. */
+  while (1)
+    {
+      if (open_section (file, &section) != 0)
+        {
+          if (section.eof)
+            break;              /* Done reading the font file. */
+          else
+            goto fail;
+        }
+
+#if FONT_DEBUG >= 2
+      grub_printf("opened section %c%c%c%c ok\n",
+                  section.name[0], section.name[1],
+                  section.name[2], section.name[3]);
+#endif
+
+      if (grub_memcmp (section.name, section_names_font_name, 4) == 0)
+        {
+          font->name = read_section_as_string (&section);
+          if (!font->name)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_max_char_width, 4) == 0)
+        {
+          if (read_section_as_short (&section, &font->max_char_width) != 0)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_max_char_height, 4) == 0)
+        {
+          if (read_section_as_short (&section, &font->max_char_height) != 0)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_ascent, 4) == 0)
+        {
+          if (read_section_as_short (&section, &font->ascent) != 0)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_descent, 4) == 0)
+        {
+          if (read_section_as_short (&section, &font->descent) != 0)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_char_index, 4) == 0)
+        {
+          /* Load the font index. */
+          if (load_font_index (file, section.length, font) != 0)
+            goto fail;
+        }
+      else if (grub_memcmp (section.name, section_names_data, 4) == 0)
+        {
+          /* When the DATA section marker is reached, we stop reading. */
+          break;
+        }
+      else
+        {
+          /* Unhandled section type, simply skip past it. */
+#if FONT_DEBUG >= 3
+          grub_printf("Unhandled section type, skipping.\n");
+#endif
+          grub_off_t section_end = grub_file_tell (file) + section.length;
+          if ((int) grub_file_seek (file, section_end) == -1)
+            goto fail;
+        }
+    }
+
+  if (!font->name)
+    {
+      grub_printf ("Note: Font has no name.\n");
+      font->name = grub_strdup ("Unknown");
+    }
+
+#if FONT_DEBUG >= 1
+  grub_printf ("Loaded font `%s'.\n"
+               "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n",
+               font->name,
+               font->ascent, font->descent,
+               font->max_char_width, font->max_char_height,
+               font->num_chars);
+#endif
+
+  if (font->max_char_width == 0
+      || font->max_char_height == 0
+      || font->num_chars == 0
+      || font->char_index == 0
+      || font->ascent == 0
+      || font->descent == 0)
+    {
+      grub_error (GRUB_ERR_BAD_FONT,
+                  "Invalid font file: missing some required data.");
+      goto fail;
+    }
+
+  /* Add the font to the global font registry. */
+  if (register_font (font) != 0)
+    goto fail;
+
+  return 0;             /* Font loaded ok. */
+
+fail:
+  free_font (font);
+  return 1;                     /* Failed to load font. */
+}
+
+/*
+   Read a 16-bit big-endian integer from FILE, convert it to native byte
+   order, and store it in *VALUE.
+   Returns 0 on success, 1 on failure.
+ */
+static int
+read_be_uint16 (grub_file_t file, grub_uint16_t * value)
+{
+  if (grub_file_read (file, (char *) value, 2) != 2)
+    return 1;
+  *value = grub_be_to_cpu16 (*value);
+  return 0;
+}
+
+static int
+read_be_int16 (grub_file_t file, grub_int16_t * value)
+{
+  /* For the signed integer version, use the same code as for unsigned. */
+  return read_be_uint16 (file, (grub_uint16_t *) value);
+}
+
+/*
+   Return a pointer to the character index entry for the glyph corresponding to
+   the codepoint CODE in the font FONT.  If not found, return zero.
+ */
+static struct char_index_entry *
+find_glyph (const grub_font_t font, grub_uint32_t code)
+{
+  grub_uint32_t i;
+  grub_uint32_t len = font->num_chars;
+  struct char_index_entry *table = font->char_index;
+
+  /* Do a linear search.  */
+  for (i = 0; i < len; i++)
+    {
+      if (table[i].code == code)
+        return &table[i];
+    }
+
+  return 0;                     /* No entry found for code point CODE. */
+}
+
+static struct grub_font_glyph *
+grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code)
+{
+  struct char_index_entry *index_entry;
+
+  index_entry = find_glyph (font, code);
+  if (index_entry)
+    {
+      struct grub_font_glyph *glyph = 0;
+      grub_uint16_t width;
+      grub_uint16_t height;
+      grub_int16_t xoff;
+      grub_int16_t yoff;
+      grub_int16_t dwidth;
+      int len;
+
+      if (index_entry->glyph)
+        return index_entry->glyph;   /* Return cached glyph. */
+
+      /* Make sure we can find glyphs for error messages.  Push active
+         error message to error stack and reset error message.  */
+      grub_error_push ();
+
+      grub_file_seek (font->file, index_entry->offset);
+
+      /* Read the glyph width, height, and baseline. */
+      if (read_be_uint16(font->file, &width) != 0
+          || read_be_uint16(font->file, &height) != 0
+          || read_be_int16(font->file, &xoff) != 0
+          || read_be_int16(font->file, &yoff) != 0
+          || read_be_int16(font->file, &dwidth) != 0)
+        {
+          //remove_font (font);
+          return 0;
+        }
+
+      len = (width * height + 7) / 8;
+      glyph = grub_malloc (sizeof (struct grub_font_glyph) + len);
+      if (! glyph)
+        {
+          //remove_font (font);
+          return 0;
+        }
+
+      glyph->font = font;
+      glyph->width = width;
+      glyph->height = height;
+      glyph->offset_x = xoff;
+      glyph->offset_y = yoff;
+      glyph->device_width = dwidth;
+
+      /* Don't try to read empty bitmaps (e.g., space characters). */
+      if (len != 0)
+        {
+          if (grub_file_read (font->file, (char *) glyph->bitmap, len) != len)
+            {
+              //remove_font (font);
+              return 0;
+            }
+        }
+
+      /* Restore old error message.  */
+      grub_error_pop ();
+
+      /* Cache the glyph. */
+      index_entry->glyph = glyph;
+
+      return glyph;  /* Glyph loaded ok. */
+    }
+
+  return 0;
+}
+
+/* Get the glyph for FONT corresponding to the Unicode code point CODE.
+   Returns a pointer to an glyph indicating there is no glyph available
+   if CODE does not exist in the font.  The glyphs are cached once loaded. */
+struct grub_font_glyph *
+grub_font_get_glyph (grub_font_t font, grub_uint32_t code)
+{
+  struct grub_font_glyph *glyph;
+  glyph = grub_font_get_glyph_internal (font, code);
+  if (glyph == 0)
+    glyph = unknown_glyph;
+  return glyph;
+}
+
+/* Get a glyph corresponding to the codepoint CODE.  If no glyph is available
+   for CODE in the available fonts, then a glyph representing an unknown
+   character is returned.  This function never returns NULL.
+   The returned glyph is owned by the font manager and should not be freed
+   by the caller.  The glyphs are cached. */
+struct grub_font_glyph *
+grub_font_get_glyph_any (grub_uint32_t code)
+{
+  struct font_node *node;
+  /* Keep track of next node, in case there's an I/O error in
+     grub_font_get_glyph() and the font is removed from the list. */
+  struct font_node *next;
+
+  for (node = grub_font_list; node; node = next)
+    {
+      grub_font_t font;
+      struct grub_font_glyph *glyph;
+
+      font = node->value;
+      next = node->next;
+
+      glyph = grub_font_get_glyph_internal (font, code);
+      if (glyph)
+        return glyph;
+    }
+
+  /* Uggh...  Glyph was not found in any font. */
+  return unknown_glyph;  /* Failed to load glyph. */
+}
+
+/*
+   Free the memory used by a font.
+   This should not be called if the font has been made available to
+   users (once it is added to the global font list), since there would
+   be the possibility of a dangling pointer.
+ */
+static void
+free_font (grub_font_t font)
+{
+  if (font)
+    {
+      if (font->file)
+        grub_file_close (font->file);
+      if (font->name)
+        grub_free (font->name);
+      if (font->char_index)
+        grub_free (font->char_index);
+      grub_free (font);
+    }
+}
+
+/*
+   Add FONT to the global font registry.
+   Returns 0 upon success, nonzero on failure (the font was not registered).
+ */
+static int
+register_font (grub_font_t font)
+{
+  struct font_node *node = 0;
+
+  node = grub_malloc (sizeof (struct font_node));
+  if (!node)
+    return 1;  /* Error. */
+
+  node->value = font;
+  node->next = grub_font_list;
+  grub_font_list = node;
+
+  return 0;  /* Success. */
+}
+
+/*
+   Remove the font from the global font list.  We don't actually free the
+   font's memory since users could be holding references to the font.
+ */
+static void
+remove_font (grub_font_t font)
+{
+  struct font_node **nextp, *cur;
+
+  for (nextp = &grub_font_list, cur = *nextp;
+       cur;
+       nextp = &cur->next, cur = cur->next)
+    {
+      if (cur->value == font)
+        {
+          *nextp = cur->next;
+
+          /* Free the node, but not the font itself. */
+          grub_free (cur);
+
+          return;
+        }
+    }
+}
+

=== removed file 'font/manager.c'
--- font/manager.c	2008-08-01 03:06:55 +0000
+++ font/manager.c	1970-01-01 00:00:00 +0000
@@ -1,283 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2003,2005,2006,2007  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/file.h>
-#include <grub/misc.h>
-#include <grub/dl.h>
-#include <grub/normal.h>
-#include <grub/types.h>
-#include <grub/mm.h>
-#include <grub/font.h>
-#include <grub/bufio.h>
-
-struct entry
-{
-  grub_uint32_t code;
-  grub_uint32_t offset;
-};
-
-struct font
-{
-  struct font *next;
-  grub_file_t file;
-  grub_uint32_t num;
-  struct entry table[0];
-};
-
-static struct font *font_list;
-
-/* Fill unknown glyph's with rounded question mark.  */
-static grub_uint8_t unknown_glyph[16] =
-{       /* 76543210 */
-  0x7C, /*  ooooo   */
-  0x82, /* o     o  */
-  0xBA, /* o ooo o  */
-  0xAA, /* o o o o  */
-  0xAA, /* o o o o  */
-  0x8A, /* o   o o  */
-  0x9A, /* o  oo o  */
-  0x92, /* o  o  o  */
-  0x92, /* o  o  o  */
-  0x92, /* o  o  o  */
-  0x92, /* o  o  o  */
-  0x82, /* o     o  */
-  0x92, /* o  o  o  */
-  0x82, /* o     o  */
-  0x7C, /*  ooooo   */
-  0x00  /*          */
-};
-
-static int
-add_font (const char *filename)
-{
-  grub_file_t file = 0;
-  char magic[4];
-  grub_uint32_t num, i;
-  struct font *font = 0;
-
-  file = grub_buffile_open (filename, 0);
-  if (! file)
-    goto fail;
-
-  if (grub_file_read (file, magic, 4) != 4)
-    goto fail;
-
-  if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0)
-    {
-      grub_error (GRUB_ERR_BAD_FONT, "invalid font magic");
-      goto fail;
-    }
-
-  if (grub_file_read (file, (char *) &num, 4) != 4)
-    goto fail;
-
-  num = grub_le_to_cpu32 (num);
-  font = (struct font *) grub_malloc (sizeof (struct font)
-				      + sizeof (struct entry) * num);
-  if (! font)
-    goto fail;
-
-  font->file = file;
-  font->num = num;
-
-  for (i = 0; i < num; i++)
-    {
-      grub_uint32_t code, offset;
-      
-      if (grub_file_read (file, (char *) &code, 4) != 4)
-	goto fail;
-
-      if (grub_file_read (file, (char *) &offset, 4) != 4)
-	goto fail;
-
-      font->table[i].code = grub_le_to_cpu32 (code);
-      font->table[i].offset = grub_le_to_cpu32 (offset);
-    }
-
-  font->next = font_list;
-  font_list = font;
-
-  return 1;
-
- fail:
-  if (font)
-    grub_free (font);
-
-  if (file)
-    grub_file_close (file);
-
-  return 0;
-}
-
-static void
-remove_font (struct font *font)
-{
-  struct font **p, *q;
-
-  for (p = &font_list, q = *p; q; p = &(q->next), q = q->next)
-    if (q == font)
-      {
-        *p = q->next;
-	
-	grub_file_close (font->file);
-	grub_free (font);
-	
-        break;
-      }
-}
-
-/* Return the offset of the glyph corresponding to the codepoint CODE
-   in the font FONT.  If no found, return zero.  */
-static grub_uint32_t
-find_glyph (const struct font *font, grub_uint32_t code)
-{
-  grub_uint32_t start = 0;
-  grub_uint32_t end = font->num - 1;
-  const struct entry *table = font->table;
-  
-  /* This shouldn't happen.  */
-  if (font->num == 0)
-    return 0;
-
-  /* Do a binary search.  */
-  while (start <= end)
-    {
-      grub_uint32_t i = (start + end) / 2;
-
-      if (table[i].code < code)
-	start = i + 1;
-      else if (table[i].code > code)
-	end = i - 1;
-      else
-	return table[i].offset;
-    }
-
-  return 0;
-}
-
-/* Set the glyph to something stupid.  */
-static void
-fill_with_default_glyph (grub_font_glyph_t glyph)
-{
-  unsigned i;
-
-  /* Use pre-defined pattern to fill unknown glyphs.  */
-  for (i = 0; i < 16; i++)
-    glyph->bitmap[i] = unknown_glyph[i];
-
-  glyph->char_width = 1;
-  glyph->width = glyph->char_width * 8;
-  glyph->height = 16;
-  glyph->baseline = (16 * 3) / 4;
-}
-
-/* Get a glyph corresponding to the codepoint CODE.  Always fill glyph
-   information with something, even if no glyph is found.  */
-int
-grub_font_get_glyph (grub_uint32_t code,
-		     grub_font_glyph_t glyph)
-{
-  struct font *font;
-  grub_uint8_t bitmap[32];
-
-  /* FIXME: It is necessary to cache glyphs!  */
-  
- restart:
-  for (font = font_list; font; font = font->next)
-    {
-      grub_uint32_t offset;
-
-      offset = find_glyph (font, code);
-      if (offset)
-	{
-	  grub_uint32_t w;
-	  int len;
-
-          /* Make sure we can find glyphs for error messages.  Push active
-             error message to error stack and reset error message.  */
-          grub_error_push ();
-	  
-	  grub_file_seek (font->file, offset);
-	  if ((len = grub_file_read (font->file, (char *) &w, sizeof (w)))
-	      != sizeof (w))
-	    {
-              remove_font (font);
-              goto restart;
-	    }
-
-	  w = grub_le_to_cpu32 (w);
-	  if (w != 1 && w != 2)
-	    {
-	      /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */
-	      remove_font (font);
-	      goto restart;
-	    }
-
-	  if (grub_file_read (font->file, (char *) bitmap, w * 16)
-	      != (grub_ssize_t) w * 16)
-	    {
-	      remove_font (font);
-	      goto restart;
-	    }
-
-          /* Fill glyph with information.  */	    
-          grub_memcpy (glyph->bitmap, bitmap, w * 16);
-          
-	  glyph->char_width = w;
-	  glyph->width = glyph->char_width * 8;
-	  glyph->height = 16;
-	  glyph->baseline = (16 * 3) / 4;
-	  
-	  /* Restore old error message.  */
-          grub_error_pop ();
-          
-	  return 1;
-	}
-    }
-
-  /* Uggh...  No font was found.  */
-  fill_with_default_glyph (glyph);
-  return 0;
-}
-
-static grub_err_t
-font_command (struct grub_arg_list *state __attribute__ ((unused)),
-	      int argc  __attribute__ ((unused)),
-	      char **args __attribute__ ((unused)))
-{
-  if (argc == 0)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
-
-  while (argc--)
-    if (! add_font (*args++))
-      return 1;
-
-  return 0;
-}
-
-GRUB_MOD_INIT(font_manager)
-{
-  grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH,
-			 "font FILE...",
-			 "Specify one or more font files to display.", 0);
-}
-
-GRUB_MOD_FINI(font_manager)
-{
-  grub_unregister_command ("font");
-}

=== modified file 'genmk.rb'
--- genmk.rb	2008-07-28 21:35:40 +0000
+++ genmk.rb	2008-08-03 03:57:46 +0000
@@ -126,7 +126,7 @@
 	$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $<
 
 #{mod_src}: moddep.lst genmodsrc.sh
-	sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
+	$(GENMODSRC) '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
 
 ifneq ($(#{prefix}_EXPORTS),no)
 #{defsym}: #{pre_obj}
@@ -158,18 +158,21 @@
 PARTMAPFILES += #{partmap}
 
 #{command}: #{src} $(#{src}_DEPENDENCIES) gencmdlist.sh
-	set -e; \
-	  $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
+	$(INFO_GENCMDLIST)
+	$(V_PREFIX)set -e; \
+	  $(_TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
 	  | sh $(srcdir)/gencmdlist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
 
 #{fs}: #{src} $(#{src}_DEPENDENCIES) genfslist.sh
-	set -e; \
-	  $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
+	$(INFO_GENFSLIST)
+	$(V_PREFIX)set -e; \
+	  $(_TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
 	  | sh $(srcdir)/genfslist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
 
 #{partmap}: #{src} $(#{src}_DEPENDENCIES) genpartmaplist.sh
-	set -e; \
-	  $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
+	$(INFO_GENPARTMAPLIST)
+	$(V_PREFIX)set -e; \
+	  $(_TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
 	  | sh $(srcdir)/genpartmaplist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
 
 

=== added directory 'gfxmenu'
=== added file 'gfxmenu/gfxmenu.c'
--- gfxmenu/gfxmenu.c	1970-01-01 00:00:00 +0000
+++ gfxmenu/gfxmenu.c	2008-07-27 00:06:20 +0000
@@ -0,0 +1,221 @@
+/* gfxmenu.c - Graphical menu interface controller. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/gfxterm.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/term.h>
+#include <grub/gfxwidgets.h>
+#include <grub/menu.h>
+#include <grub/menu_viewer.h>
+#include <grub/gfxmenu_model.h>
+#include <grub/gfxmenu_view.h>
+
+static void switch_to_text_menu (void)
+{
+  grub_env_set ("menuviewer", "terminal");
+}
+
+static void
+process_key_press (int c,
+                   grub_gfxmenu_model_t model,
+                   grub_gfxmenu_view_t view,
+                   int nested,
+                   int *should_exit)
+{
+  /* When a key is pressed, stop the timeout.  */
+  grub_gfxmenu_model_clear_timeout (model);
+
+  if (c == 'j' || c == GRUB_TERM_DOWN)
+    {
+      int i = grub_gfxmenu_model_get_selected_index (model);
+      int num_items = grub_gfxmenu_model_get_num_entries (model);
+      if (i < num_items - 1)
+        {
+          i++;
+          grub_gfxmenu_model_set_selected_index (model, i);
+        }
+    }
+  else if (c == 'k' || c == GRUB_TERM_UP)
+    {
+      int i = grub_gfxmenu_model_get_selected_index (model);
+      if (i > 0)
+        {
+          i--;
+          grub_gfxmenu_model_set_selected_index (model, i);
+        }
+    }
+  else if (c == '\r' || c == '\n' || c == GRUB_TERM_RIGHT)
+    {
+      int selected = grub_gfxmenu_model_get_selected_index (model);
+      int num_entries = grub_gfxmenu_model_get_num_entries (model);
+      if (selected >= 0 && selected < num_entries)
+        {
+          grub_menu_entry_t entry =
+            grub_gfxmenu_model_get_entry (model, selected);
+          grub_gfxmenu_view_execute_entry (view, entry);
+        }
+    }
+  else if (c == 'c')
+    {
+      grub_gfxmenu_view_run_terminal (view);
+      if (grub_errno != GRUB_ERR_NONE)
+        *should_exit = 1;
+    }
+  else if (c == 't')
+    {
+      /* The write hook for 'menuviewer' will cause
+       * grub_menu_viewer_should_return to return nonzero. */
+      switch_to_text_menu ();
+      *should_exit = 1;
+    }
+  else if (c == '1')
+    {
+      grub_gfxmenu_view_load_theme (view,
+                                    "/boot/grub/themes/proto/theme.txt");
+    }
+  else if (c == '2')
+    {
+      grub_gfxmenu_view_load_theme (view,
+                                    "/boot/grub/themes/winter/theme.txt");
+    }
+  else if (nested && c == GRUB_TERM_ESC)
+    {
+      *should_exit = 1;
+    }
+}
+
+static void
+handle_key_events (grub_gfxmenu_model_t model,
+                   grub_gfxmenu_view_t view,
+                   int nested,
+                   int *should_exit)
+{
+  while (!*should_exit && grub_checkkey () != -1)
+    {
+      int key = grub_getkey ();
+      int c = GRUB_TERM_ASCII_CHAR (key);
+      process_key_press (c, model, view, nested, should_exit);
+    }
+}
+
+static grub_err_t
+show_menu (grub_menu_t menu, int nested)
+{
+  grub_gfxmenu_model_t model;
+
+  model = grub_gfxmenu_model_new (menu);
+  if (! model)
+    {
+      grub_print_error ();
+      grub_printf ("Initializing menu data for graphical menu failed;\n"
+                   "falling back to terminal based menu.\n");
+      grub_wait_after_message ();
+      switch_to_text_menu ();
+      return grub_errno;
+    }
+
+  grub_gfxmenu_view_t view;
+
+  /* Create the view.  */
+  const char *theme_path = grub_env_get ("theme");
+  if (! theme_path)
+    theme_path = "/boot/grub/themes/proto/theme.txt";
+
+  view = grub_gfxmenu_view_new (theme_path, model);
+  if (! view)
+    {
+      grub_print_error ();
+      grub_printf ("Starting graphical menu failed;\n"
+                   "falling back to terminal based menu.\n");
+      grub_wait_after_message ();
+      grub_gfxmenu_model_destroy (model);
+      switch_to_text_menu ();
+      return grub_errno;
+    }
+
+  /* Initially select the default menu entry.  */
+  int default_index = grub_menu_get_default_entry_index (menu);
+  grub_gfxmenu_model_set_selected_index (model, default_index);
+
+  /* Start the timer to execute the default entry.  */
+  grub_gfxmenu_model_set_timeout (model);
+
+  /* Main event loop.  */
+  int exit_requested = 0;
+  while (!exit_requested && !grub_menu_viewer_should_return ())
+    {
+      if (grub_gfxmenu_model_timeout_expired (model))
+        {
+          grub_gfxmenu_model_clear_timeout (model);
+          int i = grub_gfxmenu_model_get_selected_index (model);
+          grub_menu_entry_t e = grub_gfxmenu_model_get_entry (model, i);
+          grub_gfxmenu_view_execute_with_fallback (view, e);
+          continue;
+        }
+
+      grub_gfxmenu_view_draw (view);
+      grub_video_swap_buffers ();
+      handle_key_events (model, view, nested, &exit_requested);
+    }
+
+  grub_gfxmenu_view_destroy (view);
+  grub_gfxmenu_model_destroy (model);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_gfxmenu (struct grub_arg_list *state __attribute__ ((unused)),
+                  int argc __attribute__ ((unused)),
+                  char **args __attribute__ ((unused)))
+{
+  grub_menu_t menu = grub_env_get_data_slot ("menu");
+  if (!menu)
+    return grub_error (GRUB_ERR_MENU, "No menu context");
+
+  return show_menu (menu, 1);
+}
+
+static struct grub_menu_viewer menu_viewer =
+{
+  .name = "gfxmenu",
+  .show_menu = show_menu
+};
+
+GRUB_MOD_INIT (gfxmenu)
+{
+  (void) mod;                   /* To stop warning. */
+  grub_menu_viewer_register (&menu_viewer);
+  grub_register_command ("gfxmenu",
+                         grub_cmd_gfxmenu, GRUB_COMMAND_FLAG_BOTH,
+                         "gfxmenu", "Show graphical menu interface", 0);
+}
+
+GRUB_MOD_FINI (gfxmenu)
+{
+  grub_unregister_command ("gfxmenu");
+}

=== added file 'gfxmenu/model.c'
--- gfxmenu/model.c	1970-01-01 00:00:00 +0000
+++ gfxmenu/model.c	2008-07-26 23:37:04 +0000
@@ -0,0 +1,192 @@
+/* model.c - Graphical menu interface MVC model. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/menu.h>
+#include <grub/time.h>
+#include <grub/gfxmenu_model.h>
+
+/* Model type definition.  */
+struct grub_gfxmenu_model
+{
+  grub_menu_t menu;
+  int num_entries;
+  grub_menu_entry_t *entries;
+  int selected_entry_index;
+  int timeout_set;
+  grub_uint64_t timeout_start;
+  grub_uint64_t timeout_at;
+};
+
+
+grub_gfxmenu_model_t
+grub_gfxmenu_model_new (grub_menu_t menu)
+{
+  grub_gfxmenu_model_t model;
+
+  model = grub_malloc (sizeof (*model));
+  if (! model)
+    return 0;
+
+  model->menu = menu;
+  model->num_entries = menu->size;
+  model->entries = 0;
+  model->selected_entry_index = 0;
+  model->timeout_set = 0;
+  model->timeout_at = 0;
+  if (model->num_entries > 0)
+    {
+      model->entries = grub_malloc (model->num_entries 
+                                    * sizeof (*model->entries));
+      if (! model->entries)
+        goto fail_and_free;
+
+      int i;
+      grub_menu_entry_t cur;
+      for (i = 0, cur = menu->entry_list;
+           i < model->num_entries;
+           i++, cur = cur->next)
+        {
+          model->entries[i] = cur;
+        }
+    }
+
+  return model;
+
+fail_and_free:
+  grub_free (model->entries);
+  grub_free (model);
+  return 0;
+}
+
+void
+grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model)
+{
+  if (! model)
+    return;
+
+  grub_free (model->entries);
+  model->entries = 0;
+
+  grub_free (model);
+}
+
+grub_menu_t
+grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model)
+{
+  return model->menu;
+}
+
+void
+grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model)
+{
+  int timeout_sec = grub_menu_get_timeout ();
+  if (timeout_sec >= 0)
+    {
+      model->timeout_start = grub_get_time_ms ();
+      model->timeout_at = model->timeout_start + timeout_sec * 1000;
+      model->timeout_set = 1;
+    }
+  else
+    {
+      model->timeout_set = 0;
+    }
+}
+
+void
+grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model)
+{
+  model->timeout_set = 0;
+  grub_menu_set_timeout (-1);
+}
+
+int
+grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model)
+{
+  if (!model->timeout_set)
+    return -1;
+
+  return model->timeout_at - model->timeout_start;
+}
+
+int
+grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model)
+{
+  if (!model->timeout_set)
+    return -1;
+
+  return model->timeout_at - grub_get_time_ms ();
+}
+
+int
+grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model)
+{
+  if (model->timeout_set 
+      && grub_get_time_ms () >= model->timeout_at)
+    return 1;
+
+  return 0;
+}
+
+int 
+grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model)
+{
+  return model->num_entries;
+}
+
+int 
+grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model)
+{
+  return model->selected_entry_index;
+}
+
+void 
+grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model, int index)
+{
+  model->selected_entry_index = index;
+}
+
+const char *
+grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model, int index)
+{
+  if (index < 0 || index >= model->num_entries)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index");
+      return 0;
+    }
+
+  return model->entries[index]->title;
+}
+
+grub_menu_entry_t
+grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model, int index)
+{
+  if (index < 0 || index >= model->num_entries)
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid menu index");
+      return 0;
+    }
+
+  return model->entries[index];
+}
+

=== added file 'gfxmenu/stringutil.c'
--- gfxmenu/stringutil.c	1970-01-01 00:00:00 +0000
+++ gfxmenu/stringutil.c	2008-07-26 00:44:48 +0000
@@ -0,0 +1,196 @@
+/* stringutil.c - String utilities. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/stringutil.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+/* Create a new NUL-terminated string on the heap as a substring of BUF.
+   The range of buf included is the half-open interval [START,END).
+   The index START is inclusive, END is exclusive.  */
+char *
+grub_new_substring (const char *buf,
+                    grub_size_t start, grub_size_t end)
+{
+  char *s = grub_malloc (end - start + 1);
+  if (! s)
+    return 0;
+  grub_memcpy (s, buf + start, end - start);
+  s[end - start] = '\0';
+  return s;
+}
+
+/* Eliminate "." and ".." path elements from PATH.  A new heap-allocated
+   string is returned.  */
+static char *
+canonicalize_path (const char *path)
+{
+  int i;
+  const char *p;
+  char *newpath = 0;
+
+  /* Count the path components in path.  */
+  int components = 1;
+  for (p = path; *p; p++)
+    if (*p == '/')
+      components++;
+
+  char **path_array = grub_malloc (components * sizeof (*path_array));
+  if (! path_array)
+    return 0;
+
+  /* Initialize array elements to NULL pointers; in case once of the
+     allocations fails, the cleanup code can just call grub_free() for all
+     pointers in the array.  */
+  for (i = 0; i < components; i++)
+    path_array[i] = 0;
+
+  /* Parse the path into path_array.  */
+  p = path;
+  for (i = 0; i < components && p; i++)
+    {
+      /* Find the end of the path element.  */
+      const char *end = grub_strchr (p, '/');
+      if (!end)
+        end = p + grub_strlen (p);
+
+      /* Copy the element.  */
+      path_array[i] = grub_new_substring (p, 0, end - p);
+      if (!path_array[i])
+        goto cleanup;
+
+      /* Advance p to point to the start of the next element, or NULL.  */
+      if (*end)
+        p = end + 1;
+      else
+        p = 0;
+    }
+
+  /* Eliminate '.' and '..' elements from the path array.  */
+  int newpath_length = 0;
+  for (i = components - 1; i >= 0; --i)
+    {
+      if (! grub_strcmp (path_array[i], "."))
+        {
+          grub_free (path_array[i]);
+          path_array[i] = 0;
+        }
+      else if (! grub_strcmp (path_array[i], "..")
+               && i > 0)
+        {
+          /* Delete the '..' and the prior path element.  */
+          grub_free (path_array[i]);
+          path_array[i] = 0;
+          --i;
+          grub_free (path_array[i]);
+          path_array[i] = 0;
+        }
+      else
+        {
+          newpath_length += grub_strlen (path_array[i]) + 1;
+        }
+    }
+
+  /* Construct a new path string.  */
+  newpath = grub_malloc (newpath_length + 1);
+  if (! newpath)
+    goto cleanup;
+
+  newpath[0] = '\0';
+  char *newpath_end = newpath;
+  int first = 1;
+  for (i = 0; i < components; i++)
+    {
+      char *element = path_array[i];
+      if (element)
+        {
+          /* For all components but the first, prefix with a slash.  */
+          if (! first)
+            newpath_end = grub_stpcpy (newpath_end, "/");
+          newpath_end = grub_stpcpy (newpath_end, element);
+          first = 0;
+        }
+    }
+
+cleanup:
+  for (i = 0; i < components; i++)
+    grub_free (path_array[i]);
+  grub_free (path_array);
+
+  return newpath;
+}
+
+/* Return a new heap-allocated string representing to absolute path
+   to the file referred to by PATH.  If PATH is an absolute path, then
+   the returned path is a copy of PATH.  If PATH is a relative path, then
+   BASE is with PATH used to construct the absolute path.  */
+char *
+grub_resolve_relative_path (const char *base, const char *path)
+{
+  char *abspath;
+  char *canonpath;
+  char *p;
+
+  /* If PATH is an absolute path, then just use it as is.  */
+  if (path[0] == '/' || path[0] == '(')
+    return canonicalize_path (path);
+
+  abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 1);
+  if (!abspath)
+    return 0;
+
+  /* Concatenate BASE and PATH.
+     Note that BASE is expected to have a trailing slash.  */
+  p = grub_stpcpy (abspath, base);
+  grub_stpcpy (p, path);
+
+  canonpath = canonicalize_path (abspath);
+  if (!canonpath)
+    return abspath;
+
+  grub_free (abspath);
+  return canonpath;
+}
+
+/* Get the path of the directory where the file at FILE_PATH is located.
+   FILE_PATH should refer to a file, not a directory.  The returned path
+   includes a trailing slash.
+   This does not handle GRUB "(hd0,0)" paths properly yet since it only
+   looks at slashes.  */
+char *
+grub_get_dirname (const char *file_path)
+{
+  int i;
+  int last_slash;
+
+  last_slash = -1;
+  for (i = grub_strlen (file_path) - 1; i >= 0; --i)
+    {
+      if (file_path[i] == '/')
+        {
+          last_slash = i;
+          break;
+        }
+    }
+  if (last_slash == -1)
+    return grub_strdup ("/");
+
+  return grub_new_substring (file_path, 0, last_slash + 1);
+}

=== added file 'gfxmenu/view.c'
--- gfxmenu/view.c	1970-01-01 00:00:00 +0000
+++ gfxmenu/view.c	2008-08-04 17:10:55 +0000
@@ -0,0 +1,1243 @@
+/* view.c - Graphical menu interface MVC view. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/stringutil.h>
+#include <grub/gfxterm.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/term.h>
+#include <grub/gfxwidgets.h>
+#include <grub/time.h>
+#include <grub/menu.h>
+#include <grub/menu_viewer.h>
+#include <grub/gfxmenu_view.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include <grub/luagrub.h>
+
+typedef struct grub_gfxmenu_view_icon
+{
+  const char *class_name;
+  struct grub_video_bitmap *bitmap;
+  struct grub_gfxmenu_view_icon *next;
+} *grub_gfxmenu_view_icon_t;
+
+/* Definition of the private representation of the view.  */
+struct grub_gfxmenu_view
+{
+  grub_video_rect_t screen;
+
+  int icon_width;
+  int icon_height;
+  int item_height;
+  int item_padding;
+  int item_icon_space;
+  int item_spacing;
+  grub_font_t title_font;
+  grub_font_t item_font;
+  grub_font_t selected_item_font;
+  grub_font_t status_font;
+  char *terminal_font_name;
+  grub_video_color_t title_color;
+  grub_video_color_t item_color;
+  grub_video_color_t selected_item_color;
+  grub_video_color_t status_color;
+  grub_video_color_t status_bg_color;
+  grub_video_color_t progress_bar_border_color;
+  grub_video_color_t progress_bar_fg_color;
+  grub_video_color_t progress_bar_bg_color;
+  struct grub_video_bitmap *desktop_image;
+  grub_video_color_t desktop_color;
+  grub_gfxmenu_box_t menu_box;
+  grub_gfxmenu_box_t selected_item_box;
+  grub_gfxmenu_box_t terminal_box;
+  char *title_text;
+  lua_State *lua_state;
+  char *progress_message_text;
+  char *theme_path;
+  /* Icon cache: linked list w/ dummy head node.  */
+  struct grub_gfxmenu_view_icon icon_cache;
+
+  grub_gfxmenu_model_t model;
+};
+
+static void init_terminal (grub_gfxmenu_view_t view);
+static void destroy_terminal (void);
+static grub_err_t set_graphics_mode (void);
+static grub_err_t set_text_mode (void);
+
+/* Create a new view object, loading the theme specified by THEME_PATH and
+   associating MODEL with the view.  */
+grub_gfxmenu_view_t
+grub_gfxmenu_view_new (const char *theme_path, grub_gfxmenu_model_t model)
+{
+  grub_gfxmenu_view_t view;
+
+  view = grub_malloc (sizeof (*view));
+  if (! view)
+    return 0;
+
+  set_graphics_mode ();
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  grub_video_get_viewport ((unsigned *) &view->screen.x,
+                           (unsigned *) &view->screen.y,
+                           (unsigned *) &view->screen.width,
+                           (unsigned *) &view->screen.height);
+
+  /* Clear the screen; there may be garbage left over in video memory, and
+     loading the menu style (particularly the background) can take a while. */
+  grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
+                        view->screen.x, view->screen.y,
+                        view->screen.width, view->screen.height);
+  grub_video_swap_buffers ();
+
+  grub_font_t default_font;
+  grub_video_color_t default_fg_color;
+  grub_video_color_t default_bg_color;
+
+  default_font = grub_font_get ("Helvetica 12");
+  default_fg_color = grub_video_map_rgb (0, 0, 0);
+  default_bg_color = grub_video_map_rgb (255, 255, 255);
+
+  view->icon_width = 32;
+  view->icon_height = 32;
+  view->item_height = 42;
+  view->item_padding = 14;
+  view->item_icon_space = 4;
+  view->item_spacing = 16;
+  view->title_font = default_font;
+  view->item_font = default_font;
+  view->selected_item_font = default_font;
+  view->status_font = default_font;
+  view->terminal_font_name = grub_strdup ("Fixed 10");
+  view->title_color = default_fg_color;
+  view->item_color = default_fg_color;
+  view->selected_item_color = default_fg_color;
+  view->status_color = default_bg_color;
+  view->status_bg_color = default_fg_color;
+  view->progress_bar_border_color = default_fg_color;
+  view->progress_bar_fg_color = grub_video_map_rgb (160, 160, 160);
+  view->progress_bar_bg_color = default_bg_color;
+  view->desktop_image = 0;
+  view->desktop_color = default_bg_color;
+  view->menu_box = 0;
+  view->selected_item_box = 0;
+  view->terminal_box = 0;
+  view->title_text = grub_strdup ("GRUB Boot Menu");
+  view->lua_state = 0;
+  view->progress_message_text = 0;
+  view->theme_path = 0;
+  view->icon_cache.class_name = 0;
+  view->icon_cache.bitmap = 0;
+  view->icon_cache.next = 0;
+
+  view->model = model;
+
+  if (! grub_gfxmenu_view_load_theme (view, theme_path))
+    {
+      grub_gfxmenu_view_destroy (view);
+      return 0;
+    }
+
+  init_terminal (view);
+
+  return view;
+}
+
+static void
+free_icon_cache (grub_gfxmenu_view_t view)
+{
+  grub_gfxmenu_view_icon_t cur;
+  grub_gfxmenu_view_icon_t next;
+  for (cur = view->icon_cache.next; cur; cur = next)
+    {
+      next = cur->next;
+      grub_free (cur);
+    }
+  view->icon_cache.next = 0;
+}
+
+/* Destroy the view object.  All used memory is freed.  */
+void
+grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
+{
+  grub_video_bitmap_destroy (view->desktop_image);
+  if (view->menu_box)
+    view->menu_box->destroy (view->menu_box);
+  if (view->selected_item_box)
+    view->selected_item_box->destroy (view->selected_item_box);
+  if (view->terminal_box)
+    view->terminal_box->destroy (view->terminal_box);
+  grub_free (view->terminal_font_name);
+  grub_free (view->title_text);
+  if (view->lua_state)
+    lua_close (view->lua_state);
+  grub_free (view->progress_message_text);
+  grub_free (view->theme_path);
+  free_icon_cache (view);
+  grub_free (view);
+
+  set_text_mode ();
+  destroy_terminal ();
+}
+
+/* Sets MESSAGE as the progress message for the view.  The string MESSAGE
+   must be heap-allocated and will be owned by VIEW.  MESSAGE can be 0, in
+   which case no message is displayed.  */
+static void
+set_progress_message (grub_gfxmenu_view_t view, char *message)
+{
+  grub_free (view->progress_message_text);
+  view->progress_message_text = message;
+}
+
+/* Parse a color string of the form "r, g, b".
+   Whitespace is insignificant.  */
+static grub_video_color_t
+parse_color (const char *s)
+{
+  int red = grub_strtoul (s, 0, 0);
+  if ((s = grub_strchr (s, ',')) == 0)
+    goto fail;
+  s++;
+  int green = grub_strtoul (s, 0, 0);
+  if ((s = grub_strchr (s, ',')) == 0)
+    goto fail;
+  s++;
+  int blue = grub_strtoul (s, 0, 0);
+  int alpha;
+  if ((s = grub_strchr (s, ',')) == 0)
+    alpha = 255;
+  else
+    {
+      s++;
+      alpha = grub_strtoul (s, 0, 0);
+    }
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  return grub_video_map_rgba (red, green, blue, alpha);
+
+fail:
+  return 0;
+}
+
+/* Construct a new box widget using PATTERN to find the pixmap files for it,
+   storing the new widget at *BOXPTR.  PATTERN should be of the form:
+   "somewhere/style*.png".  The '*' then gets substituted with the various
+   pixmap names that the widget uses.
+   Return zero on failure, nonzero on success.  */
+static int
+theme_set_box (grub_gfxmenu_box_t *boxptr,
+               char *pattern, const char *theme_dir)
+{
+  char *abspattern;
+  char *prefix;
+  char *suffix;
+  char *star;
+  grub_gfxmenu_box_t box;
+
+  abspattern = grub_resolve_relative_path (theme_dir, pattern);
+  if (! abspattern)
+    return 0;
+
+  star = grub_strchr (abspattern, '*');
+  if (! star)
+    {
+      grub_free (abspattern);
+      return 0;
+    }
+
+  /* Prefix:  Get the part before the '*'.  */
+  prefix = grub_malloc (star - abspattern + 1);
+  if (! prefix)
+    {
+      grub_free (abspattern);
+      return 0;
+    }
+
+  grub_memcpy (prefix, abspattern, star - abspattern);
+  prefix[star - abspattern] = '\0';
+
+  /* Suffix:  Everything after the '*' is the suffix.  */
+  suffix = star + 1;
+
+  box = grub_gfxmenu_create_box (prefix, suffix);
+  grub_free (abspattern);   /* Note: suffix, star point into abspattern.  */
+  grub_free (prefix);
+  if (! box)
+    return 0;
+
+  if (*boxptr)
+    (*boxptr)->destroy (*boxptr);
+  *boxptr = box;
+  return 1;
+
+}
+
+/* Load the contents of the file located at PATH.  Allocates a buffer and
+   stores it in *BUFP and returns the size.  Returns -1 on error.  */
+static grub_ssize_t
+load_file (const char *path, char **bufp)
+{
+  *bufp = 0;
+
+  grub_file_t f;
+  grub_errno = GRUB_ERR_NONE;
+  f = grub_file_open (path);
+  grub_errno = GRUB_ERR_NONE;
+  if (! f)
+    return -1;
+
+  grub_size_t sz = grub_file_size (f);
+  char *buf = grub_malloc (sz);
+  if (! buf)
+    {
+      grub_file_close (f);
+      return -1;
+    }
+  grub_ssize_t n = grub_file_read (f, buf, sz);
+  if ((grub_size_t) n != sz)
+    {
+      grub_free (buf);
+      grub_file_close (f);
+      return -1;
+    }
+  grub_file_close (f);
+  *bufp = buf;
+  return n;
+}
+
+/* Load the Lua script at PATH as a chunk of Lua code.  This results in a
+   function being pushed on the Lua stack.  */
+static int
+grub_lua_load_file (lua_State *L, const char *path)
+{
+  /* Load the contents of the file.  */
+  char *buf;
+  grub_ssize_t n;
+  n = load_file (path, &buf);
+  if (n == -1)
+    return -1;
+
+  /* Create a Lua function from it.  */
+  int err;
+  err = luaL_loadbuffer (L, buf, n, path);
+  grub_free (buf);
+  if (err)
+    {
+      grub_error (GRUB_ERR_FILE_READ_ERROR, "Error loading Lua code");
+      lua_pop (L, 1);   /* Pop the error message.  */
+      return -1;
+    }
+  return 0;
+}
+
+/* Error message buffer for debugging -- we should implement something
+   better, but this really helps debugging the theme loading by providing
+   some details on errors when things go wrong.  */
+static char errbuf[400];
+
+/* Set the specified property NAME on the view to the given string VALUE.
+   This function takes ownership of both NAME and VALUE, so the caller
+   should pass pointers to new heap-allocated strings.  */
+static void
+theme_set_string (grub_gfxmenu_view_t view, char *name, char *value,
+                  const char *theme_dir)
+{
+  if (! grub_strcmp ("title-font", name))
+    view->title_font = grub_font_get (value);
+  else if (! grub_strcmp ("item-font", name))
+    view->item_font = grub_font_get (value);
+  else if (! grub_strcmp ("selected-item-font", name))
+    view->selected_item_font = grub_font_get (value);
+  else if (! grub_strcmp ("status-font", name))
+    view->status_font = grub_font_get (value);
+  else if (! grub_strcmp ("terminal-font", name))
+    {
+      grub_free (view->terminal_font_name);
+      view->terminal_font_name = value;
+      value = 0;  /* Prevent value from being freed below.  */
+    }
+  else if (! grub_strcmp ("title-color", name))
+    view->title_color = parse_color (value);
+  else if (! grub_strcmp ("item-color", name))
+    view->item_color = parse_color (value);
+  else if (! grub_strcmp ("selected-item-color", name))
+    view->selected_item_color = parse_color (value);
+  else if (! grub_strcmp ("status-color", name))
+    view->status_color = parse_color (value);
+  else if (! grub_strcmp ("status-bg-color", name))
+    view->status_bg_color = parse_color (value);
+  else if (! grub_strcmp ("progress-bar-border-color", name))
+    view->progress_bar_border_color = parse_color (value);
+  else if (! grub_strcmp ("progress-bar-fg-color", name))
+    view->progress_bar_fg_color = parse_color (value);
+  else if (! grub_strcmp ("progress-bar-bg-color", name))
+    view->progress_bar_bg_color = parse_color (value);
+  else if (! grub_strcmp ("desktop-image", name))
+    {
+      struct grub_video_bitmap *raw_bitmap;
+      struct grub_video_bitmap *scaled_bitmap;
+      char *path;
+      path = grub_resolve_relative_path (theme_dir, value);
+      if (! path)
+        goto fail;
+      if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
+        {
+          grub_free (path);
+          goto fail;
+        }
+      grub_free(path);
+      grub_video_bitmap_create_scaled (&scaled_bitmap,
+                                       view->screen.width,
+                                       view->screen.height,
+                                       raw_bitmap,
+                                       GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+      grub_video_bitmap_destroy (raw_bitmap);
+      if (!scaled_bitmap)
+        goto fail;
+
+      grub_video_bitmap_destroy (view->desktop_image);
+      view->desktop_image = scaled_bitmap;
+    }
+  else if (! grub_strcmp ("desktop-color", name))
+    view->desktop_color = parse_color (value);
+  else if (! grub_strcmp ("menu-box", name))
+    theme_set_box (&view->menu_box, value, theme_dir);
+  else if (! grub_strcmp ("selected-item-box", name))
+    theme_set_box (&view->selected_item_box, value, theme_dir);
+  else if (! grub_strcmp ("terminal-box", name))
+    theme_set_box (&view->terminal_box, value, theme_dir);
+  else if (! grub_strcmp ("title-text", name))
+    {
+      grub_free (view->title_text);
+      view->title_text = value;
+      value = 0;  /* Prevent value from being freed below.  */
+    }
+  else if (! grub_strcmp ("lua-script", name))
+    {
+      grub_error_push ();
+      /* The 'lua-script' attribute specifies a Lua source file to load.  */
+      if (! view->lua_state)
+        {
+          view->lua_state = lua_open ();
+          if (! view->lua_state)
+            goto fail;
+          luaL_openlibs (view->lua_state);
+          grub_lua_load_grub_packages (view->lua_state);
+        }
+
+      /* Load the file.  */
+      char *path;
+      path = grub_resolve_relative_path (theme_dir, value);
+      if (! path)
+        goto fail;
+      if (grub_lua_load_file (view->lua_state, path) != 0)
+        {
+          grub_strcat (errbuf, "lua script load failed. ");
+          grub_error (GRUB_ERR_FILE_READ_ERROR, "load script failed");
+          grub_free (path);
+          goto fail;
+        }
+      grub_free (path);
+
+      /* Execute the loaded chunk of Lua code.  */
+      int err;
+      err = lua_pcall (view->lua_state, 0, 0, 0);
+      if (err)
+        {
+          grub_strcat (errbuf, "script failed: ");
+          grub_strcat (errbuf, lua_tostring (view->lua_state, -1));
+          goto fail;
+        }
+    }
+
+fail:
+  grub_free (value);
+  grub_free (name);
+}
+
+/* Set the specified property NAME on the view to the given numeric VALUE.
+   This function takes ownership NAME, so the caller should pass a pointer
+   to a new heap-allocated string.  */
+static void
+theme_set_number (grub_gfxmenu_view_t view, char *name, int value)
+{
+  if (! grub_strcmp ("icon-width", name))
+    view->icon_width = value;
+  else if (! grub_strcmp ("icon-height", name))
+    view->icon_height = value;
+  else if (! grub_strcmp ("item-height", name))
+    view->item_height = value;
+  else if (! grub_strcmp ("item-padding", name))
+    view->item_padding = value;
+  else if (! grub_strcmp ("item-icon-space", name))
+    view->item_icon_space = value;
+  else if (! grub_strcmp ("item-spacing", name))
+    view->item_spacing = value;
+
+  grub_free (name);
+}
+
+/* Set properties on the view based on settings from the specified
+   theme file.  Returns nonzero on success, zero on failure.  */
+int
+grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
+{
+  char *theme_dir;
+  grub_file_t file;
+  char *buf;
+  int pos;
+  int len;
+
+  if (view->lua_state)
+    {
+      lua_close (view->lua_state);
+      view->lua_state = 0;
+    }
+
+  errbuf[0] = '\0';   /* Clear the error messages.  */
+  theme_dir = grub_get_dirname (theme_path);
+
+  file = grub_file_open (theme_path);
+  if (!file)
+    {
+      grub_free (theme_dir);
+      return 0;
+    }
+
+  len = grub_file_size (file);
+  buf = grub_malloc (len);
+  if (! buf)
+    {
+      grub_file_close (file);
+      grub_free (theme_dir);
+      return 0;
+    }
+  if (grub_file_read (file, buf, len) != len)
+    {
+      grub_free (buf);
+      grub_file_close (file);
+      grub_free (theme_dir);
+      return 0;
+    }
+
+  pos = 0;
+  while (pos < len)
+    {
+      /* Skip comments (lines beginning with #).  */
+      if (pos < len && buf[pos] == '#')
+        goto nextline;
+
+      /* Get name.  */
+      /* Find a word character.  */
+      while (pos < len && grub_isspace(buf[pos]))
+        pos++;
+      int name_start = pos;
+      /* Find the end of the name.  */
+      while (pos < len
+             && (grub_isalpha(buf[pos])
+                 || grub_isdigit(buf[pos])
+                 || buf[pos] == '_'
+                 || buf[pos] == '-'))
+        pos++;
+      int name_end = pos;
+
+      if (name_end - name_start < 1)
+        goto nextline;
+
+      /* Skip whitespace before separator.  */
+      while (pos < len
+             && (buf[pos] == ' '
+                 || buf[pos] == '\t'
+                 || buf[pos] == '\f'))
+        pos++;
+
+      /* Read separator.  */
+      if (buf[pos] != ':')
+        goto nextline;
+
+      pos++;  /* Skip separator.  */
+
+      /* Skip whitespace after separator.  */
+      while (pos < len
+             && (buf[pos] == ' '
+                 || buf[pos] == '\t'
+                 || buf[pos] == '\f'))
+        pos++;
+
+      /* Get the value based on its type.  */
+      if (pos < len && buf[pos] == '"')
+        {
+          /* String value.  (e.g., '"My string"')  */
+
+          int value_start;
+          int value_end;
+
+          /* Skip the opening quotation mark.  */
+          pos++;
+          /* Get string value.  */
+          value_start = pos;
+          /* Find the ending quotation mark.  */
+          while (pos < len
+                 && !(buf[pos] == '"'
+                      || buf[pos] == '\n'))
+            pos++;
+          value_end = pos;
+          theme_set_string (view,
+                            grub_new_substring (buf, name_start, name_end),
+                            grub_new_substring (buf, value_start, value_end),
+                            theme_dir);
+        }
+      else if (pos < len && grub_isdigit(buf[pos]))
+        {
+          /* Numeric value.  (e.g., '123')  */
+
+          int value_start;
+          int value_end;
+          char *value_str;
+          int value;
+
+          /* Get numeric value.  */
+          value_start = pos;
+          /* Find the end of the digit sequence.  */
+          while (pos < len && grub_isdigit(buf[pos]))
+            pos++;
+          value_end = pos;
+          value_str = grub_new_substring (buf, value_start, value_end);
+          if (!value_str)
+            continue;
+          value = grub_strtoul (value_str, 0, 0);
+          grub_free (value_str);
+          theme_set_number (view,
+                            grub_new_substring (buf, name_start, name_end),
+                            value);
+        }
+
+nextline:
+      /* Eat characters up to the newline.  */
+      while (pos < len && buf[pos] != '\n')
+        pos++;
+      pos++;   /* Eat the newline.  */
+    }
+
+  grub_free (view->theme_path);
+  view->theme_path = grub_strdup (theme_path);
+  free_icon_cache (view);   /* There may be new icons for this theme.  */
+  grub_free (buf);
+  grub_file_close (file);
+  grub_free (theme_dir);
+
+  return 1;
+}
+
+static void
+draw_background (grub_gfxmenu_view_t view)
+{
+  if (view->desktop_image)
+    {
+      struct grub_video_bitmap *img = view->desktop_image;
+      grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
+                              view->screen.x, view->screen.y, 0, 0,
+                              grub_video_bitmap_get_width (img),
+                              grub_video_bitmap_get_height (img));
+    }
+  else
+    {
+      grub_video_fill_rect (view->desktop_color,
+                            view->screen.x, view->screen.y,
+                            view->screen.width, view->screen.height);
+    }
+}
+
+static void
+draw_lua_desktop (grub_gfxmenu_view_t view)
+{
+  lua_State *L = view->lua_state;
+  if (! L)
+    return;   /* No Lua state, just return.  */
+
+  lua_getglobal (L, "theme");
+  if (! lua_isnoneornil (L, -1))
+    {
+      lua_getfield (L, -1, "draw_desktop");
+      if (! lua_isnoneornil (L, -1))
+        {
+          lua_getglobal (L, "theme");
+          if (! lua_isnoneornil (L, -1))
+            {
+              /* We should check the return value of lua_pcall(), but we don't
+                 have a good way to handle the error anyway, so for now we don't.  */
+              if (lua_pcall (L, 1, 0, 0) != 0)
+                {
+                  /* Display the error message.  */
+                  grub_strcpy (errbuf, lua_tostring (L, -1));
+                }
+            }
+        }
+    }
+
+  lua_settop (L, 0);   /* Clear the stack.  */
+}
+
+static const char icon_extension[] = ".png";
+
+static struct grub_video_bitmap *
+try_loading_icon (grub_gfxmenu_view_t view,
+                  const char *dir, const char *class_name)
+{
+  char *path = grub_malloc (grub_strlen (dir)
+                            + grub_strlen (class_name)
+                            + grub_strlen (icon_extension)
+                            + 100);
+  if (! path)
+    return 0;
+
+  grub_strcpy (path, dir);
+  grub_strcat (path, class_name);
+  grub_strcat (path, icon_extension);
+
+  struct grub_video_bitmap *raw_bitmap;
+  grub_video_bitmap_load (&raw_bitmap, path);
+  grub_free (path);
+  grub_errno = GRUB_ERR_NONE;  /* Critical to clear the error!!  */
+  if (! raw_bitmap)
+    return 0;
+
+  struct grub_video_bitmap *scaled_bitmap;
+  grub_video_bitmap_create_scaled (&scaled_bitmap,
+                                   view->icon_width, view->icon_height,
+                                   raw_bitmap,
+                                   GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+  grub_video_bitmap_destroy (raw_bitmap);
+  if (! scaled_bitmap)
+    return 0;
+
+  return scaled_bitmap;
+}
+
+static struct grub_video_bitmap *
+get_icon_by_class (grub_gfxmenu_view_t view, const char *class_name)
+{
+
+  /* First check the view's icon cache.  */
+  grub_gfxmenu_view_icon_t vicon;
+  for (vicon = view->icon_cache.next; vicon; vicon = vicon->next)
+    {
+      if (grub_strcmp (vicon->class_name, class_name) == 0)
+        return vicon->bitmap;
+    }
+
+  /* Otherwise, we search for an icon to load.  */
+  if (! view->theme_path)
+    return 0;
+
+  char *theme_dir = grub_get_dirname (view->theme_path);
+  char *icons_dir;
+  struct grub_video_bitmap *icon;
+  icon = 0;
+  /* First try the theme's own icons, from "grub/themes/NAME/icons/"  */
+  icons_dir = grub_resolve_relative_path (theme_dir, "icons/");
+  if (icons_dir)
+    {
+      icon = try_loading_icon (view, icons_dir, class_name);
+      grub_free (icons_dir);
+    }
+  if (! icon)
+    {
+      /* If the theme doesn't have an appropriate icon, check in
+         "grub/themes/icons".  */
+      icons_dir = grub_resolve_relative_path (theme_dir, "../icons/");
+      if (icons_dir)
+        {
+          icon = try_loading_icon (view, icons_dir, class_name);
+          grub_free (icons_dir);
+        }
+    }
+  grub_free (theme_dir);
+
+  if (! icon)
+    return 0;
+
+  vicon = grub_malloc (sizeof (*vicon));
+  if (! vicon)
+    {
+      grub_video_bitmap_destroy (icon);
+      return 0;
+    }
+  vicon->class_name = class_name;
+  vicon->bitmap = icon;
+  vicon->next = view->icon_cache.next;
+  view->icon_cache.next = vicon;   /* Link it into the cache.  */
+  return vicon->bitmap;
+}
+
+static struct grub_video_bitmap *
+get_item_icon (grub_gfxmenu_view_t view, int item_index)
+{
+  grub_menu_entry_t entry;
+  entry = grub_gfxmenu_model_get_entry (view->model, item_index);
+  if (! entry)
+    return 0;
+
+  struct grub_menu_entry_class *c;
+  struct grub_video_bitmap *icon;
+  icon = 0;
+  for (c = entry->classes->next; c && ! icon; c = c->next)
+    icon = get_icon_by_class (view, c->name);
+  return icon;
+}
+
+static void
+draw_menu (grub_gfxmenu_view_t view)
+{
+  int boxpad = view->item_padding;
+  int icon_text_space = view->item_icon_space;
+  int item_vspace = view->item_spacing;
+
+  int ascent = grub_font_get_ascent (view->item_font);
+  int descent = grub_font_get_descent (view->item_font);
+  int item_height = view->item_height;
+
+  int num_items = grub_gfxmenu_model_get_num_entries (view->model);
+  grub_video_rect_t r;
+  r.width = view->screen.width * 4 / 5;
+  /* Set the menu box height to fit the items.  */
+  r.height = (item_height * num_items
+              + item_vspace * (num_items - 1)
+              + 2 * boxpad);
+  r.x = (view->screen.width - r.width) / 2;
+  r.y = (view->screen.height - r.height) / 2;
+  view->menu_box->set_content_size (view->menu_box, r.width, r.height);
+
+  int menu_box_left_pad = view->menu_box->get_left_pad (view->menu_box);
+  int menu_box_top_pad = view->menu_box->get_top_pad (view->menu_box);
+  view->menu_box->draw (view->menu_box,
+                        r.x - menu_box_left_pad, r.y - menu_box_top_pad);
+
+  int item_top = r.y + boxpad;
+  int item_left = r.x + boxpad;
+  int i;
+
+  for (i = 0; i < num_items; i++)
+    {
+      int is_selected =
+        (i == grub_gfxmenu_model_get_selected_index (view->model));
+
+      if (is_selected)
+        {
+          view->selected_item_box->set_content_size (view->selected_item_box,
+                                                     r.width - 2 * boxpad,
+                                                     item_height);
+          int leftpad = view->selected_item_box->get_left_pad (view->selected_item_box);
+          int toppad = view->selected_item_box->get_top_pad (view->selected_item_box);
+          view->selected_item_box->draw (view->selected_item_box,
+                                         item_left - leftpad,
+                                         item_top - toppad);
+        }
+
+      struct grub_video_bitmap *icon;
+      if ((icon = get_item_icon (view, i)) != 0)
+        grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND,
+                                item_left,
+                                item_top + (item_height - view->icon_height) / 2,
+                                0, 0, view->icon_width, view->icon_height);
+
+      const char *item_title =
+        grub_gfxmenu_model_get_entry_title (view->model, i);
+      grub_video_draw_string (item_title,
+                              (is_selected
+                               ? view->selected_item_font
+                               : view->item_font),
+                              (is_selected
+                               ? view->selected_item_color
+                               : view->item_color),
+                              item_left + view->icon_width + icon_text_space,
+                              (item_top + (item_height - (ascent + descent))
+                               / 2 + ascent));
+
+      item_top += item_height + item_vspace;
+    }
+}
+
+static void
+draw_title (grub_gfxmenu_view_t view)
+{
+  if (! view->title_text)
+    return;
+
+  /* Center the title. */
+  int title_width = grub_font_get_string_width (view->title_font,
+                                                view->title_text);
+  int x = (view->screen.width - title_width) / 2;
+  int y = 40 + grub_font_get_ascent (view->title_font);
+  grub_video_draw_string (view->title_text,
+                          view->title_font, view->title_color,
+                          x, y);
+}
+
+static void
+draw_status (grub_gfxmenu_view_t view)
+{
+  int descent = grub_font_get_descent (view->status_font);
+  int ascent = grub_font_get_ascent (view->status_font);
+  int vpad = 5;
+  int textheight = descent + ascent + 1;
+  int h = 2 * vpad + 2 * textheight;
+
+  grub_video_fill_rect (view->status_bg_color,
+                        0, view->screen.height - h,
+                        view->screen.width, view->screen.height - 1);
+
+  int texty = view->screen.height - h + vpad + ascent;
+  grub_video_draw_string ("Select an item with the arrow keys and "
+                          "press Enter to boot.",
+                          view->status_font, view->status_color, 30, texty);
+  texty += textheight;
+  grub_video_draw_string ("Press:  'c' for command line; 't' to switch to "
+                          "non-graphical menu.",
+                          view->status_font, view->status_color, 30, texty);
+}
+
+static void
+draw_timeout (grub_gfxmenu_view_t view)
+{
+  int timeout = grub_gfxmenu_model_get_timeout_ms (view->model);
+  if (timeout == -1)
+    return;
+
+  int remaining = grub_gfxmenu_model_get_timeout_remaining_ms (view->model);
+  if (remaining < 0)
+    remaining = 0;
+
+  int t = timeout - remaining;
+
+  /* Set the timeout bar's frame.  */
+  grub_video_rect_t f;
+  f.width = view->screen.width * 3 / 5;
+  f.height = view->screen.height / 25;
+  f.x = view->screen.x + (view->screen.width - f.width) / 2;
+  f.y = view->screen.y + view->screen.height - 90;
+
+  /* First attempt just uses filled rectangles;
+     TODO we should enhance with a pixmap themed progress bar component.  */
+
+  /* Border.  */
+  grub_video_fill_rect (view->progress_bar_border_color,
+                        f.x - 1, f.y - 1,
+                        f.width + 2, f.height + 2);
+
+  /* Bar background.  */
+  int barwidth = f.width * t / timeout;
+  grub_video_fill_rect (view->progress_bar_bg_color,
+                        f.x + barwidth, f.y,
+                        f.width - barwidth, f.height);
+
+  /* Bar foreground.  */
+  grub_video_fill_rect (view->progress_bar_fg_color,
+                        f.x, f.y,
+                        barwidth, f.height);
+
+  char *text = grub_malloc (200);
+  if (!text)
+    return;
+  int seconds_remaining_rounded_up = (remaining + 999) / 1000;
+  grub_sprintf (text,
+                "The highlighted entry will be booted automatically in %d s.",
+                seconds_remaining_rounded_up);
+  grub_font_t font = view->status_font;
+  grub_video_color_t color = view->progress_bar_border_color;
+
+  /* Center the text. */
+  int text_width = grub_font_get_string_width (font, text);
+  int x = f.x + (f.width - text_width) / 2;
+  int y = (f.y + (f.height - grub_font_get_descent (font)) / 2
+           + grub_font_get_ascent (font) / 2);
+  grub_video_draw_string (text, font, color, x, y);
+  grub_free (text);
+}
+
+static void
+draw_message (grub_gfxmenu_view_t view)
+{
+  char *text = view->progress_message_text;
+  if (! text)
+    return;
+
+  grub_font_t font = view->status_font;
+  grub_video_color_t color = view->status_color;
+
+  /* Set the timeout bar's frame.  */
+  grub_video_rect_t f;
+  f.width = view->screen.width * 4 / 5;
+  f.height = 50;
+  f.x = view->screen.x + (view->screen.width - f.width) / 2;
+  f.y = view->screen.y + view->screen.height - 90 - 20 - f.height;
+
+  /* Border.  */
+  grub_video_fill_rect (color,
+                        f.x-1, f.y-1, f.width+2, f.height+2);
+  /* Fill.  */
+  grub_video_fill_rect (view->status_bg_color,
+                        f.x, f.y, f.width, f.height);
+
+  /* Center the text. */
+  int text_width = grub_font_get_string_width (font, text);
+  int x = f.x + (f.width - text_width) / 2;
+  int y = (f.y + (f.height - grub_font_get_descent (font)) / 2
+           + grub_font_get_ascent (font) / 2);
+  grub_video_draw_string (text, font, color, x, y);
+}
+
+
+void
+grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
+{
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  draw_background (view);
+  draw_lua_desktop (view);
+  draw_menu (view);
+  draw_title (view);
+  draw_status (view);
+  draw_timeout (view);
+  draw_message (view);
+
+  /* Draw error messages if there are any.  */
+  if (errbuf[0])
+    grub_video_draw_string (errbuf,
+                            view->status_font, view->title_color,
+                            10,20);
+}
+
+static grub_err_t
+set_graphics_mode (void)
+{
+  const char *doublebuf_str = grub_env_get ("doublebuffering");
+  int doublebuf_flags =
+    (doublebuf_str && doublebuf_str[0] == 'n')
+    ? 0
+    : GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+
+  const char *modestr = grub_env_get ("gfxmode");
+  if (grub_video_setup_preferred_mode (modestr, doublebuf_flags, 640, 480)
+      != GRUB_ERR_NONE)
+    return grub_errno;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+set_text_mode (void)
+{
+  return grub_video_restore ();
+}
+
+static int term_target_width;
+static int term_target_height;
+static struct grub_video_render_target *term_target;
+static int term_initialized;
+static grub_term_t term_original;
+static grub_gfxmenu_view_t term_view;
+
+static void
+repaint_terminal (int x __attribute ((unused)),
+                  int y __attribute ((unused)),
+                  int width __attribute ((unused)),
+                  int height __attribute ((unused)))
+{
+  if (! term_view)
+    return;
+
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  grub_gfxmenu_view_draw (term_view);
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
+  int termx = term_view->screen.x
+    + term_view->screen.width * (10 - 7) / 10 / 2;
+  int termy = term_view->screen.y
+    + term_view->screen.height * (10 - 7) / 10 / 2;
+
+  grub_gfxmenu_box_t term_box = term_view->terminal_box;
+  if (term_box)
+    {
+      term_box->set_content_size (term_box,
+                                  term_target_width, term_target_height);
+
+      term_box->draw (term_box,
+                      termx - term_box->get_left_pad (term_box),
+                      termy - term_box->get_top_pad (term_box));
+    }
+
+  grub_video_blit_render_target (term_target, GRUB_VIDEO_BLIT_REPLACE,
+                                 termx, termy,
+                                 0, 0, term_target_width, term_target_height);
+  grub_video_swap_buffers ();
+}
+
+static void
+init_terminal (grub_gfxmenu_view_t view)
+{
+  term_original = grub_term_get_current ();
+
+  term_target_width = view->screen.width * 7 / 10;
+  term_target_height = view->screen.height * 7 / 10;
+
+  grub_video_create_render_target (&term_target,
+                                   term_target_width,
+                                   term_target_height,
+                                   GRUB_VIDEO_MODE_TYPE_RGB
+                                   | GRUB_VIDEO_MODE_TYPE_ALPHA);
+  if (grub_errno != GRUB_ERR_NONE)
+    return;
+
+  /* Note: currently there is no API for changing the gfxterm font
+     on the fly, so whatever font the initially loaded theme specifies
+     will be permanent.  */
+  grub_gfxterm_init_window (term_target, 0, 0,
+                            term_target_width, term_target_height,
+                            view->terminal_font_name, 3);
+  if (grub_errno != GRUB_ERR_NONE)
+    return;
+  term_initialized = 1;
+
+  /* XXX: store static pointer to the 'view' object so the repaint callback can access it.  */
+  term_view = view;
+  grub_gfxterm_set_repaint_callback (repaint_terminal);
+  grub_term_set_current (grub_gfxterm_get_term ());
+}
+
+static void destroy_terminal (void)
+{
+  term_view = 0;
+  if (term_initialized)
+    grub_gfxterm_destroy_window ();
+  grub_gfxterm_set_repaint_callback (0);
+  if (term_target)
+    grub_video_delete_render_target (term_target);
+  if (term_original)
+    grub_term_set_current (term_original);
+}
+
+
+static void
+notify_booting (void *userdata, grub_menu_entry_t entry)
+{
+  grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
+
+  char *s = grub_malloc (100 + grub_strlen (entry->title));
+  if (!s)
+    return;
+
+  grub_sprintf (s, "Booting '%s'", entry->title);
+  set_progress_message (view, s);
+  grub_gfxmenu_view_draw (view);
+  grub_video_swap_buffers ();
+}
+
+static void
+notify_fallback (void *userdata, grub_menu_entry_t entry)
+{
+  grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata;
+
+  char *s = grub_malloc (100 + grub_strlen (entry->title));
+  if (!s)
+    return;
+
+  grub_sprintf (s, "Falling back to '%s'", entry->title);
+  set_progress_message (view, s);
+  grub_gfxmenu_view_draw (view);
+  grub_video_swap_buffers ();
+}
+
+static void
+notify_execution_failure (void *userdata __attribute__ ((unused)))
+{
+}
+
+
+static struct grub_menu_execute_callback execute_callback =
+{
+  .notify_booting = notify_booting,
+  .notify_fallback = notify_fallback,
+  .notify_failure = notify_execution_failure
+};
+
+int
+grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view,
+                                         grub_menu_entry_t entry)
+{
+  grub_menu_execute_with_fallback (grub_gfxmenu_model_get_menu (view->model),
+                                   entry, &execute_callback, (void *) view);
+
+  if (set_graphics_mode () != GRUB_ERR_NONE)
+    return 0;  /* Failure.  */
+
+  /* If we returned, there was a failure.  */
+  set_progress_message (view, grub_strdup ("Unable to automatically boot.  "
+                                           "Press SPACE to continue."));
+  grub_gfxmenu_view_draw (view);
+  grub_video_swap_buffers ();
+  while (GRUB_TERM_ASCII_CHAR(grub_getkey ()) != ' ')
+    {
+      /* Wait for SPACE to be pressed.  */
+    }
+
+  set_progress_message (view, 0);   /* Clear the message.  */
+
+  return 1;   /* Ok.  */
+}
+
+int
+grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view,
+                                 grub_menu_entry_t entry)
+{
+  /* Currently we switch back to text mode by restoring
+     the original terminal before executing the menu entry.
+     It is hard to make it work when executing a menu entry
+     that switches video modes -- it using gfxterm in a
+     window, the repaint callback seems to crash GRUB. */
+  /* TODO: Determine if this works when 'gfxterm' was set as
+     the current terminal before invoking the gfxmenu. */
+  destroy_terminal ();
+
+  grub_menu_execute_entry (entry);
+  if (grub_errno != GRUB_ERR_NONE)
+    grub_wait_after_message ();
+
+  if (set_graphics_mode () != GRUB_ERR_NONE)
+    return 0;  /* Failure.  */
+
+  init_terminal (view);
+  return 1;   /* Ok.  */
+}
+
+void
+grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view __attribute__((unused)))
+{
+  grub_cmdline_run (1);
+}
+

=== added file 'gfxmenu/widget-box.c'
--- gfxmenu/widget-box.c	1970-01-01 00:00:00 +0000
+++ gfxmenu/widget-box.c	2008-07-19 18:25:18 +0000
@@ -0,0 +1,244 @@
+/* widget_box.c - Pixmap-stylized box widget. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/gfxwidgets.h>
+
+enum box_pixmaps
+{
+  BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW,
+  BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W,
+  BOX_PIXMAP_CENTER
+};
+
+static const char *box_pixmap_names[] = {
+  /* Corners: */
+  "nw", "ne", "se", "sw",
+  /* Sides: */
+  "n", "e", "s", "w",
+  /* Center: */
+  "c"
+};
+
+#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names))
+
+static void
+draw (grub_gfxmenu_box_t self, int x, int y)
+{
+  int height_n;
+  int height_s;
+  int height_e;
+  int height_w;
+  int width_n;
+  int width_s;
+  int width_e;
+  int width_w;
+  unsigned i;
+
+  /* Don't try to draw if any pixmaps are null, except the center. */
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      if (i != BOX_PIXMAP_CENTER && self->scaled_pixmaps[i] == 0)
+        return;
+    }
+
+  height_n = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_N]);
+  height_s = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_S]);
+  height_e = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_E]);
+  height_w = grub_video_bitmap_get_height (self->scaled_pixmaps[BOX_PIXMAP_W]);
+  width_n = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_N]);
+  width_s = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_S]);
+  width_e = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_E]);
+  width_w = grub_video_bitmap_get_width (self->scaled_pixmaps[BOX_PIXMAP_W]);
+
+  /* Draw sides.  */
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_N], 
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w, y, 0, 0, width_n, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_S],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w, y + height_n + height_w,
+                          0, 0, width_s, height_s);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_E],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y + height_n,
+                          0, 0, width_e, height_e);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_W],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y + height_n, 0, 0, width_w, height_w);
+
+  /* Draw corners.  */
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_NW],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y, 0, 0, width_w, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_NE],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y, 
+                          0, 0, width_e, height_n);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_SE],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x + width_w + width_n, y + height_n + height_e, 
+                          0, 0, width_e, height_s);
+  grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_SW],
+                          GRUB_VIDEO_BLIT_BLEND,
+                          x, y + height_n + height_w, 
+                          0, 0, width_w, height_s);
+
+  /* Draw center.  */
+  if (self->scaled_pixmaps[BOX_PIXMAP_CENTER])
+    grub_video_blit_bitmap (self->scaled_pixmaps[BOX_PIXMAP_CENTER],
+                            GRUB_VIDEO_BLIT_BLEND,
+                            x + width_w, y + height_n,
+                            0, 0, self->width, self->height);
+}
+
+static void
+scale_pixmap (grub_gfxmenu_box_t self, int i, int w, int h)
+{
+  struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i];
+  struct grub_video_bitmap *raw = self->raw_pixmaps[i];
+
+  if (raw == 0)
+    return;
+
+  if (w == -1)
+    w = grub_video_bitmap_get_width (raw);
+  if (h == -1)
+    h = grub_video_bitmap_get_height (raw);
+
+  if (*scaled == 0 
+      || ((int) grub_video_bitmap_get_width (*scaled) != w)
+      || ((int) grub_video_bitmap_get_height (*scaled) != h))
+    {
+      if (*scaled)
+        {
+          grub_video_bitmap_destroy (*scaled);
+          *scaled = 0;
+        }
+      grub_video_bitmap_create_scaled (scaled, w, h, raw, 
+                                       GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+    }
+}
+
+static void
+set_content_size (grub_gfxmenu_box_t self,
+                  int width, int height)
+{
+  self->width = width;
+  self->height = height;
+  /* Resize sides to match the width and height.  */
+  /* It is assumed that the corners width/height match the adjacent sides.  */
+
+  /* Resize N and S sides to match width.  */
+  scale_pixmap(self, BOX_PIXMAP_N, width, -1);
+  scale_pixmap(self, BOX_PIXMAP_S, width, -1);
+
+  /* Resize E and W sides to match height.  */
+  scale_pixmap(self, BOX_PIXMAP_E, -1, height);
+  scale_pixmap(self, BOX_PIXMAP_W, -1, height);
+
+  /* Don't scale the corners--they are assumed to match the sides. */
+  scale_pixmap(self, BOX_PIXMAP_NW, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_SW, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_NE, -1, -1);
+  scale_pixmap(self, BOX_PIXMAP_SE, -1, -1);
+
+  /* Scale the center area. */
+  scale_pixmap(self, BOX_PIXMAP_CENTER, width, height);
+}
+
+static int
+get_left_pad (grub_gfxmenu_box_t self)
+{
+  return grub_video_bitmap_get_width (self->raw_pixmaps[BOX_PIXMAP_W]);
+}
+
+static int
+get_top_pad (grub_gfxmenu_box_t self)
+{
+  return grub_video_bitmap_get_height (self->raw_pixmaps[BOX_PIXMAP_N]);
+}
+
+static void
+destroy (grub_gfxmenu_box_t self)
+{
+  unsigned i;
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      if (self->raw_pixmaps[i])
+        grub_video_bitmap_destroy(self->raw_pixmaps[i]);
+      self->raw_pixmaps[i] = 0;
+
+      if (self->scaled_pixmaps[i])
+        grub_video_bitmap_destroy(self->scaled_pixmaps[i]);
+      self->scaled_pixmaps[i] = 0;
+    }
+  grub_free (self->raw_pixmaps);
+  self->raw_pixmaps = 0;
+  grub_free (self->scaled_pixmaps);
+  self->scaled_pixmaps = 0;
+
+  grub_free (self);             /* Free self:  must be the last step! */
+}
+
+
+grub_gfxmenu_box_t
+grub_gfxmenu_create_box (const char *pixmaps_prefix,
+                         const char *pixmaps_suffix)
+{
+  char path[200];
+  unsigned i;
+  grub_gfxmenu_box_t box;
+
+  box = (grub_gfxmenu_box_t) grub_malloc (sizeof (*box));
+  if (!box)
+    return 0;
+  box->width = 0;
+  box->height = 0;
+  box->raw_pixmaps =
+    (struct grub_video_bitmap **) 
+    grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
+  box->scaled_pixmaps =
+    (struct grub_video_bitmap **)
+    grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *));
+
+  for (i = 0; i < BOX_NUM_PIXMAPS; i++)
+    {
+      /* TODO XXX dynamically allocate PATH, making sure it's large enough */
+      grub_sprintf (path, "%s%s%s",
+                    pixmaps_prefix, box_pixmap_names[i], pixmaps_suffix);
+      grub_video_bitmap_load (&box->raw_pixmaps[i], path);
+      box->scaled_pixmaps[i] = 0;
+    }
+
+  box->draw = draw;
+  box->set_content_size = set_content_size;
+  box->get_left_pad = get_left_pad;
+  box->get_top_pad = get_top_pad;
+  box->destroy = destroy;
+
+  return box;
+}
+

=== added file 'include/grub/bitmap_scale.h'
--- include/grub/bitmap_scale.h	1970-01-01 00:00:00 +0000
+++ include/grub/bitmap_scale.h	2008-07-03 14:27:43 +0000
@@ -0,0 +1,54 @@
+/* bitmap_scale.h - Bitmap scaling functions. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BITMAP_SCALE_HEADER
+#define GRUB_BITMAP_SCALE_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/bitmap_scale.h>
+
+enum grub_video_bitmap_scale_method
+{
+  /* Choose the fastest interpolation algorithm. */
+  GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST,
+  /* Choose the highest quality interpolation algorithm. */
+  GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST,
+  /* Nearest neighbor interpolation algorithm. */
+  GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST,
+  /* Bilinear interpolation algorithm. */
+  GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR
+};
+
+grub_err_t
+grub_video_bitmap_scale_nn (struct grub_video_bitmap *dst,
+                            struct grub_video_bitmap *src);
+
+grub_err_t
+grub_video_bitmap_scale_bilinear (struct grub_video_bitmap *dst,
+                                  struct grub_video_bitmap *src);
+
+grub_err_t
+grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
+                                 int dst_width, int dst_height,
+                                 struct grub_video_bitmap *src,
+                                 enum
+                                 grub_video_bitmap_scale_method scale_method);
+
+#endif /* ! GRUB_BITMAP_SCALE_HEADER */

=== modified file 'include/grub/font.h'
--- include/grub/font.h	2007-07-21 22:32:33 +0000
+++ include/grub/font.h	2008-07-03 14:17:31 +0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2003,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2003,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,33 +21,85 @@
 
 #include <grub/types.h>
 
-#define GRUB_FONT_MAGIC	"PPF\x7f"
+/* Forward declaration of opaque structure grub_font.
+ * Users only pass struct grub_font pointers to the font module functions,
+ * and do not have knowledge of the structure contents. */
+struct grub_font;
+
+/* Font type used to access font functions. */
+typedef struct grub_font *grub_font_t;
+
 
 struct grub_font_glyph
 {
-  /* Glyph width in pixels.  */
-  grub_uint8_t width;
-  
-  /* Glyph height in pixels.  */
-  grub_uint8_t height;
-  
-  /* Glyph width in characters.  */
-  grub_uint8_t char_width;
-  
-  /* Glyph baseline position in pixels (from up).  */
-  grub_uint8_t baseline;
-  
-  /* Glyph bitmap data array of bytes in ((width + 7) / 8) * height.
-     Bitmap is formulated by height scanlines, each scanline having
-     width number of pixels. Pixels are coded as bits, value 1 meaning
-     of opaque pixel and 0 is transparent. If width does not fit byte
-     boundary, it will be padded with 0 to make it fit.  */
-  grub_uint8_t bitmap[32];
+  /* Reference to the font this glyph belongs to. */
+  grub_font_t font;
+
+  /* Glyph bitmap width in pixels. */
+  grub_uint16_t width;
+
+  /* Glyph bitmap height in pixels. */
+  grub_uint16_t height;
+
+  /* Glyph bitmap x offset in pixels.  Add to screen coordinate. */
+  grub_int16_t offset_x;
+
+  /* Glyph bitmap y offset in pixels.  Subtract from screen coordinate.  */
+  grub_int16_t offset_y;
+
+  /* Number of pixels to advance to start the next character. */
+  grub_uint16_t device_width;
+
+  /* Row-major order, packed bits (no padding; rows can break within a byte).
+   * The length of the array is (width * height + 7) / 8.  Within a
+   * byte, the most significant bit is the first (leftmost/uppermost) pixel.
+   * Pixels are coded as bits, value 1 meaning of opaque pixel and 0 is
+   * transparent. If the length of the array does not fit byte boundary, it
+   * will be padded with 0 bits to make it fit.  */
+  grub_uint8_t bitmap[0];
 };
 
-typedef struct grub_font_glyph *grub_font_glyph_t;
-
-int grub_font_get_glyph (grub_uint32_t code,
-			 grub_font_glyph_t glyph);
+
+/****** font/font.c ******/
+
+/* Get the font that has the specified name.  Font names are in the form
+ * "Family Name Bold Italic 14", where Bold and Italic are optional.
+ * If no font matches the name specified, the most recently loaded font
+ * is returned as a fallback. */
+grub_font_t grub_font_get (const char *font_name);
+
+const char *grub_font_get_name (grub_font_t font);
+
+int grub_font_get_max_char_width (grub_font_t font);
+
+int grub_font_get_max_char_height (grub_font_t font);
+
+int grub_font_get_ascent (grub_font_t font);
+
+int grub_font_get_descent (grub_font_t font);
+
+int grub_font_get_string_width (grub_font_t font, const char *str);
+
+
+/****** font/loader.c ******/
+
+/*
+ * Load a font and add it to the beginning of the global font list.
+ * Returns: 0 upon success; nonzero upon failure.
+ */
+int grub_font_load (const char *filename);
+
+/* Get the glyph for FONT corresponding to the Unicode code point CODE.
+ * Returns a pointer to an glyph indicating there is no glyph available
+ * if CODE does not exist in the font.  The glyphs are cached once loaded. */
+struct grub_font_glyph *grub_font_get_glyph (grub_font_t font,
+                                             grub_uint32_t code);
+
+/* Get a glyph corresponding to the codepoint CODE.  If no glyph is available
+ * for CODE in the available fonts, then a glyph representing an unknown
+ * character is returned.  This function never returns NULL.
+ * The returned glyph is owned by the font manager and should not be freed
+ * by the caller.  The glyphs are cached. */
+struct grub_font_glyph *grub_font_get_glyph_any (grub_uint32_t code);
 
 #endif /* ! GRUB_FONT_HEADER */

=== added file 'include/grub/font_internal.h'
--- include/grub/font_internal.h	1970-01-01 00:00:00 +0000
+++ include/grub/font_internal.h	2008-07-03 14:16:11 +0000
@@ -0,0 +1,71 @@
+/* font_internal.h - Font declarations for use internally by the font module.
+ * Users of the font module should not include this header. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_FONT_INTERNAL_HEADER
+#define GRUB_FONT_INTERNAL_HEADER 1
+
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/font.h>
+
+#define FONT_DEBUG 0
+
+struct char_index_entry
+{
+  grub_uint32_t code;
+  grub_uint8_t storage_flags;
+  grub_uint32_t offset;
+  struct grub_font_glyph *glyph;   /* Glyph if loaded, or null. */
+};
+
+struct grub_font
+{
+  char *name;
+  grub_file_t file;
+  short max_char_width;
+  short max_char_height;
+  short ascent;
+  short descent;
+  grub_uint32_t num_chars;
+  struct char_index_entry *char_index;
+};
+
+struct font_node
+{
+  struct font_node *next;
+  struct grub_font *value;
+};
+
+extern struct font_node *grub_font_list;
+
+
+/****** loader.c ******/
+
+/* Initialize the font loader module. */
+void
+grub_font_loader_init (void);
+
+
+#endif /* ! GRUB_FONT_INTERNAL_HEADER */
+

=== added file 'include/grub/gfxmenu_model.h'
--- include/grub/gfxmenu_model.h	1970-01-01 00:00:00 +0000
+++ include/grub/gfxmenu_model.h	2008-07-26 23:37:04 +0000
@@ -0,0 +1,59 @@
+/* gfxmenu_model.h - gfxmenu model interface. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXMENU_MODEL_HEADER
+#define GRUB_GFXMENU_MODEL_HEADER 1
+
+#include <grub/menu.h>
+
+struct grub_gfxmenu_model;   /* Forward declaration of opaque type.  */
+typedef struct grub_gfxmenu_model *grub_gfxmenu_model_t;
+
+
+grub_gfxmenu_model_t grub_gfxmenu_model_new (grub_menu_t menu);
+
+void grub_gfxmenu_model_destroy (grub_gfxmenu_model_t model);
+
+grub_menu_t grub_gfxmenu_model_get_menu (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_set_timeout (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_clear_timeout (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_timeout_ms (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_timeout_remaining_ms (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_timeout_expired (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_num_entries (grub_gfxmenu_model_t model);
+
+int grub_gfxmenu_model_get_selected_index (grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_model_set_selected_index (grub_gfxmenu_model_t model,
+                                            int index);
+
+const char *grub_gfxmenu_model_get_entry_title (grub_gfxmenu_model_t model,
+                                                int index);
+
+grub_menu_entry_t grub_gfxmenu_model_get_entry (grub_gfxmenu_model_t model,
+                                                int index);
+
+#endif /* GRUB_GFXMENU_MODEL_HEADER */
+

=== added file 'include/grub/gfxmenu_view.h'
--- include/grub/gfxmenu_view.h	1970-01-01 00:00:00 +0000
+++ include/grub/gfxmenu_view.h	2008-07-26 23:37:04 +0000
@@ -0,0 +1,53 @@
+/* gfxmenu_view.h - gfxmenu view interface. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXMENU_VIEW_HEADER
+#define GRUB_GFXMENU_VIEW_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/menu.h>
+#include <grub/gfxmenu_model.h>
+
+struct grub_gfxmenu_view;   /* Forward declaration of opaque type.  */
+typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t;
+
+
+grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path,
+                                           grub_gfxmenu_model_t model);
+
+void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view);
+
+/* Set properties on the view based on settings from the specified
+   theme file. */
+int grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view,
+                                  const char *theme_path);
+
+void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view);
+
+int grub_gfxmenu_view_execute_with_fallback (grub_gfxmenu_view_t view,
+                                             grub_menu_entry_t entry);
+
+int grub_gfxmenu_view_execute_entry (grub_gfxmenu_view_t view,
+                                     grub_menu_entry_t entry);
+
+void grub_gfxmenu_view_run_terminal (grub_gfxmenu_view_t view);
+
+#endif /* GRUB_GFXMENU_VIEW_HEADER */
+

=== added file 'include/grub/gfxterm.h'
--- include/grub/gfxterm.h	1970-01-01 00:00:00 +0000
+++ include/grub/gfxterm.h	2008-07-19 19:56:06 +0000
@@ -0,0 +1,41 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXTERM_HEADER
+#define GRUB_GFXTERM_HEADER	1
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/term.h>
+#include <grub/video.h>
+
+grub_err_t
+grub_gfxterm_init_window (struct grub_video_render_target *target,
+                          int x, int y, int width, int height, 
+                          const char *font_name, int border_width);
+
+void grub_gfxterm_destroy_window (void);
+
+grub_term_t grub_gfxterm_get_term (void);
+
+typedef void (*grub_gfxterm_repaint_callback_t)(int x, int y, 
+                                                int width, int height);
+
+void grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func);
+
+#endif /* ! GRUB_GFXTERM_HEADER */

=== added file 'include/grub/gfxwidgets.h'
--- include/grub/gfxwidgets.h	1970-01-01 00:00:00 +0000
+++ include/grub/gfxwidgets.h	2008-07-19 18:25:18 +0000
@@ -0,0 +1,47 @@
+/* gfxwidgets.h - Widgets for the graphical menu (gfxmenu).  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXWIDGETS_HEADER
+#define GRUB_GFXWIDGETS_HEADER 1
+
+#include <grub/video.h>
+
+typedef struct grub_gfxmenu_box *grub_gfxmenu_box_t;
+
+struct grub_gfxmenu_box
+{
+  /* The size of the content.  */
+  int width;
+  int height;
+
+  struct grub_video_bitmap **raw_pixmaps;
+  struct grub_video_bitmap **scaled_pixmaps;
+
+  void (*draw) (grub_gfxmenu_box_t self, int x, int y);
+  void (*set_content_size) (grub_gfxmenu_box_t self,
+                            int width, int height);
+  int (*get_left_pad) (grub_gfxmenu_box_t self);
+  int (*get_top_pad) (grub_gfxmenu_box_t self);
+  void (*destroy) (grub_gfxmenu_box_t self);
+};
+
+grub_gfxmenu_box_t grub_gfxmenu_create_box (const char *pixmaps_prefix,
+                                            const char *pixmaps_suffix);
+
+#endif /* ! GRUB_GFXWIDGETS_HEADER */

=== modified file 'include/grub/i386/pc/vbeblit.h'
--- include/grub/i386/pc/vbeblit.h	2007-07-21 22:32:33 +0000
+++ include/grub/i386/pc/vbeblit.h	2008-07-09 17:27:53 +0000
@@ -25,55 +25,93 @@
 struct grub_video_i386_vbeblit_info;
 
 void
-grub_video_i386_vbeblit_R8G8B8A8_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
-                                           struct grub_video_i386_vbeblit_info *src,
-                                           int x, int y, int width, int height,
-                                           int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_R8G8B8X8_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
-                                           struct grub_video_i386_vbeblit_info *src,
-                                           int x, int y, int width, int height,
-                                           int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
-                                         struct grub_video_i386_vbeblit_info *src,
-                                         int x, int y, int width, int height,
-                                         int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
-                                         struct grub_video_i386_vbeblit_info *src,
-                                         int x, int y, int width, int height,
-                                         int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_index_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
-                                        struct grub_video_i386_vbeblit_info *src,
-                                        int x, int y, int width, int height,
-                                        int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_index_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
-                                        struct grub_video_i386_vbeblit_info *src,
-                                        int x, int y, int width, int height,
-                                        int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
-                                         struct grub_video_i386_vbeblit_info *src,
-                                         int x, int y, int width, int height,
-                                         int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
-                                       struct grub_video_i386_vbeblit_info *src,
-                                       int x, int y, int width, int height,
-                                       int offset_x, int offset_y);
-
-void
-grub_video_i386_vbeblit_index_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_BGRX8888_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
+                                           struct grub_video_i386_vbeblit_info *src,
+                                           int x, int y, int width, int height,
+                                           int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_BGRA8888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_BGR888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
+                                       struct grub_video_i386_vbeblit_info *src,
+                                       int x, int y, int width, int height,
+                                       int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_BGRA8888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                           struct grub_video_i386_vbeblit_info *src,
+                                           int x, int y, int width, int height,
+                                           int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_BGR888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_BGR888_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_RGBA8888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                           struct grub_video_i386_vbeblit_info *src,
+                                           int x, int y, int width, int height,
+                                           int offset_x, int offset_y);
+
+/* Direct copy for compatible 32 bpp blit formats.
+ * (RGBA8888->RGBA8888, BGRA8888->BGRA8888, etc.) */
+void
+grub_video_i386_vbeblit_direct32_copy (struct grub_video_i386_vbeblit_info *dst,
+                                       struct grub_video_i386_vbeblit_info *src,
+                                       int x, int y, int width, int height,
+                                       int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_RGB888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_RGB888_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_index_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                        struct grub_video_i386_vbeblit_info *src,
+                                        int x, int y, int width, int height,
+                                        int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_index_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
+                                        struct grub_video_i386_vbeblit_info *src,
+                                        int x, int y, int width, int height,
+                                        int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_RGBA8888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
+                                         struct grub_video_i386_vbeblit_info *src,
+                                         int x, int y, int width, int height,
+                                         int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_RGB888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
+                                       struct grub_video_i386_vbeblit_info *src,
+                                       int x, int y, int width, int height,
+                                       int offset_x, int offset_y);
+
+void
+grub_video_i386_vbeblit_index_RGB888 (struct grub_video_i386_vbeblit_info *dst,
                                       struct grub_video_i386_vbeblit_info *src,
                                       int x, int y, int width, int height,
                                       int offset_x, int offset_y);

=== modified file 'include/grub/i386/pc/vbefill.h'
--- include/grub/i386/pc/vbefill.h	2007-07-21 22:32:33 +0000
+++ include/grub/i386/pc/vbefill.h	2008-07-03 13:49:18 +0000
@@ -25,14 +25,14 @@
 struct grub_video_i386_vbeblit_info;
 
 void
-grub_video_i386_vbefill_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbefill_direct32 (struct grub_video_i386_vbeblit_info *dst,
                                   grub_video_color_t color,  int x, int y,
                                   int width, int height);
 
 void
-grub_video_i386_vbefill_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
-                                grub_video_color_t color, int x, int y,
-                                int width, int height);
+grub_video_i386_vbefill_direct24 (struct grub_video_i386_vbeblit_info *dst,
+                                  grub_video_color_t color, int x, int y,
+                                  int width, int height);
 
 void
 grub_video_i386_vbefill_index (struct grub_video_i386_vbeblit_info *dst,

=== added file 'include/grub/i386/tsc.h'
--- include/grub/i386/tsc.h	1970-01-01 00:00:00 +0000
+++ include/grub/i386/tsc.h	2008-07-28 16:23:46 +0000
@@ -0,0 +1,80 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TSC_HEADER
+#define KERNEL_CPU_TSC_HEADER   1
+
+#include <grub/types.h>
+
+/* Read the TSC value, which increments with each CPU clock cycle. */
+static __inline grub_uint64_t
+grub_get_tsc (void)
+{
+  grub_uint32_t lo, hi;
+
+  /* The CPUID instruction is a 'serializing' instruction, and
+     avoids out-of-order execution of the RDTSC instruction. */
+  __asm__ __volatile__ ("xorl %%eax, %%eax\n\t"
+                        "cpuid":::"%rax", "%rbx", "%rcx", "%rdx");
+  /* Read TSC value.  We cannot use "=A", since this would use
+     %rax on x86_64. */
+  __asm__ __volatile__ ("rdtsc":"=a" (lo), "=d" (hi));
+
+  return (((grub_uint64_t) hi) << 32) | lo;
+}
+
+static __inline int
+grub_cpu_is_cpuid_supported (void)
+{
+  grub_uint32_t id_supported;
+
+  __asm__ ("pushfl\n\t"
+           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
+           "movl %%eax, %%ecx      /* Save original flags in ECX */\n\t"
+           "xorl $0x200000, %%eax  /* Flip ID bit in EFLAGS */\n\t"
+           "pushl %%eax            /* Store modified EFLAGS on stack */\n\t"
+           "popfl                  /* Replace current EFLAGS */\n\t"
+           "pushfl                 /* Read back the EFLAGS */\n\t"
+           "popl %%eax             /* Get EFLAGS into EAX */\n\t"
+           "xorl %%ecx, %%eax      /* Check if flag could be modified */\n\t"
+           : "=a" (id_supported)
+           : /* No inputs.  */
+           : /* Clobbered:  */ "%rcx");
+
+  return id_supported != 0;
+}
+
+static __inline int
+grub_cpu_is_tsc_supported (void)
+{
+  if (! grub_cpu_is_cpuid_supported ())
+    return 0;
+
+  grub_uint32_t features;
+  __asm__ ("movl $1, %%eax\n\t"
+           "cpuid"
+           : "=d" (features)
+           : /* No inputs.  */
+           : /* Clobbered:  */ "%rax", "%rbx", "%rcx");
+  return (features & (1 << 4)) != 0;
+}
+
+void grub_tsc_init (void);
+grub_uint64_t grub_tsc_get_time_ms (void);
+
+#endif /* ! KERNEL_CPU_TSC_HEADER */

=== modified file 'include/grub/i386/types.h'
--- include/grub/i386/types.h	2007-07-21 22:32:33 +0000
+++ include/grub/i386/types.h	2008-08-01 15:27:27 +0000
@@ -25,6 +25,51 @@
 /* The size of long.  */
 #define GRUB_TARGET_SIZEOF_LONG		4
 
+/* The native word size in bits.  */
+#define __WORDSIZE 32
+
+/* These assume 8-bit `char's, 16-bit `short int's,
+   and 32-bit `int's and `long int's.  */
+
+/* Number of bits in a `char'.	*/
+#define CHAR_BIT 8
+
+/* Minimum and maximum values a `signed char' can hold.  */
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold.  (Minimum is 0.)  */
+#define UCHAR_MAX 255
+
+/* Minimum and maximum values a `char' can hold.  */
+#ifdef __CHAR_UNSIGNED__
+# define CHAR_MIN 0
+# define CHAR_MAX UCHAR_MAX
+#else
+# define CHAR_MIN SCHAR_MIN
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+/* Minimum and maximum values for signed short int.  */
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+/* Maximum value for unsigned short int.  (Minimum is 0.)  */
+#define USHRT_MAX 65535
+
+/* Mininum and maximum values for signed int.  */
+#define INT_MIN   (-INT_MAX - 1)
+#define INT_MAX   2147483647
+#define UINT_MAX  4294967295U
+
+/* Mininum and maximum values for signed long.  */
+#if __WORDSIZE == 64
+# define LONG_MAX 9223372036854775807L
+#else
+# define LONG_MAX 2147483647L
+#endif
+#define LONG_MIN  (-LONG_MAX - 1L)
+
 /* i386 is little-endian.  */
 #undef GRUB_TARGET_WORDS_BIGENDIAN
 

=== added file 'include/grub/luagrub.h'
--- include/grub/luagrub.h	1970-01-01 00:00:00 +0000
+++ include/grub/luagrub.h	2008-08-04 17:10:55 +0000
@@ -0,0 +1,27 @@
+/* luagrub.h - prototypes for GRUB Lua package functions.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LUAGRUB_HEADER
+#define GRUB_LUAGRUB_HEADER	1
+
+#include <lua.h>
+
+int grub_lua_load_grub_packages (lua_State *L);
+
+#endif /* GRUB_LUAGRUB_HEADER */

=== added file 'include/grub/menu.h'
--- include/grub/menu.h	1970-01-01 00:00:00 +0000
+++ include/grub/menu.h	2008-08-03 02:14:40 +0000
@@ -0,0 +1,63 @@
+/* menu.h - Menu and menu entry model declarations. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MENU_HEADER
+#define GRUB_MENU_HEADER 1
+
+struct grub_menu_entry_class
+{
+  char *name;
+  struct grub_menu_entry_class *next;
+};
+
+/* The menu entry.  */
+struct grub_menu_entry
+{
+  /* The title name.  */
+  const char *title;
+
+  /* The classes associated with the menu entry:
+     used to choose an icon or other style attributes.
+     This is a dummy head node for the linked list, so for an entry E,
+     E.classes->next is the first class if it is not NULL.  */
+  struct grub_menu_entry_class *classes;
+
+  /* The commands associated with this menu entry.  */
+  struct grub_script *commands;
+
+  /* The sourcecode of the menu entry, used by the editor.  */
+  const char *sourcecode;
+
+  /* The next element.  */
+  struct grub_menu_entry *next;
+};
+typedef struct grub_menu_entry *grub_menu_entry_t;
+
+/* The menu.  */
+struct grub_menu
+{
+  /* The size of a menu.  */
+  int size;
+
+  /* The list of menu entries.  */
+  grub_menu_entry_t entry_list;
+};
+typedef struct grub_menu *grub_menu_t;
+
+#endif /* GRUB_MENU_HEADER */

=== added file 'include/grub/menu_viewer.h'
--- include/grub/menu_viewer.h	1970-01-01 00:00:00 +0000
+++ include/grub/menu_viewer.h	2008-07-19 19:07:47 +0000
@@ -0,0 +1,48 @@
+/* menu_viewer.h - Interface to menu viewer implementations. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MENU_VIEWER_HEADER
+#define GRUB_MENU_VIEWER_HEADER 1
+
+#include <grub/err.h>
+#include <grub/symbol.h>
+#include <grub/types.h>
+#include <grub/menu.h>
+
+struct grub_menu_viewer
+{
+  /* The menu viewer name.  */
+  const char *name;
+
+  grub_err_t (*show_menu) (grub_menu_t menu, int nested);
+
+  struct grub_menu_viewer *next;
+};
+typedef struct grub_menu_viewer *grub_menu_viewer_t;
+
+void EXPORT_FUNC(grub_menu_viewer_init) (void);
+
+void EXPORT_FUNC(grub_menu_viewer_register) (grub_menu_viewer_t viewer);
+
+grub_err_t EXPORT_FUNC(grub_menu_viewer_show_menu) (grub_menu_t menu, int nested);
+
+/* Return nonzero iff the menu viewer should clean up and return ASAP. */
+int EXPORT_FUNC(grub_menu_viewer_should_return) (void);
+
+#endif /* GRUB_MENU_VIEWER_HEADER */

=== modified file 'include/grub/misc.h'
--- include/grub/misc.h	2008-07-04 01:12:54 +0000
+++ include/grub/misc.h	2008-08-01 15:27:27 +0000
@@ -52,11 +52,14 @@
 char *EXPORT_FUNC(grub_strstr) (const char *haystack, const char *needle);
 int EXPORT_FUNC(grub_iswordseparator) (int c);
 int EXPORT_FUNC(grub_isspace) (int c);
+int EXPORT_FUNC(grub_iscntrl) (int c);
 int EXPORT_FUNC(grub_isprint) (int c);
 int EXPORT_FUNC(grub_isalpha) (int c);
+int EXPORT_FUNC(grub_isalnum) (int c);
 int EXPORT_FUNC(grub_isgraph) (int c);
 int EXPORT_FUNC(grub_isdigit) (int c);
 int EXPORT_FUNC(grub_tolower) (int c);
+long EXPORT_FUNC(grub_strtol) (const char *str, char **end, int base);
 unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base);
 unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base);
 char *EXPORT_FUNC(grub_strdup) (const char *s);

=== modified file 'include/grub/normal.h'
--- include/grub/normal.h	2008-03-26 12:01:02 +0000
+++ include/grub/normal.h	2008-08-03 04:00:22 +0000
@@ -25,6 +25,7 @@
 #include <grub/err.h>
 #include <grub/arg.h>
 #include <grub/env.h>
+#include <grub/menu.h>
 
 /* The maximum size of a command-line.  */
 #define GRUB_MAX_CMDLINE	1600
@@ -39,7 +40,7 @@
 #define GRUB_COMMAND_FLAG_TITLE		0x4
 /* Don't print the command on booting.  */
 #define GRUB_COMMAND_FLAG_NO_ECHO	0x8
-/* Don't print the command on booting.  */
+/* Pass arguments to the command without parsing options.  */
 #define GRUB_COMMAND_FLAG_NO_ARG_PARSE	0x10
 /* Not loaded yet. Used for auto-loading.  */
 #define GRUB_COMMAND_FLAG_NOT_LOADED	0x20
@@ -84,34 +85,6 @@
 };
 typedef struct grub_command *grub_command_t;
 
-/* The menu entry.  */
-struct grub_menu_entry
-{
-  /* The title name.  */
-  const char *title;
-
-    /* The commands associated with this menu entry.  */
-  struct grub_script *commands;
-
-  /* The sourcecode of the menu entry, used by the editor.  */
-  const char *sourcecode;
-
-  /* The next element.  */
-  struct grub_menu_entry *next;
-};
-typedef struct grub_menu_entry *grub_menu_entry_t;
-
-/* The menu.  */
-struct grub_menu
-{
-  /* The size of a menu.  */
-  int size;
-
-  /* The list of menu entries.  */
-  grub_menu_entry_t entry_list;
-};
-typedef struct grub_menu *grub_menu_t;
-
 /* This is used to store the names of filesystem modules for auto-loading.  */
 struct grub_fs_module_list
 {
@@ -123,10 +96,27 @@
 /* To exit from the normal mode.  */
 extern grub_jmp_buf grub_exit_env;
 
+extern struct grub_menu_viewer grub_normal_terminal_menu_viewer;
+
+typedef struct grub_menu_execute_callback
+{
+  void (*notify_booting) (void *userdata, grub_menu_entry_t entry);
+  void (*notify_fallback) (void *userdata, grub_menu_entry_t entry);
+  void (*notify_failure) (void *userdata);
+} 
+*grub_menu_execute_callback_t;
+
 void grub_enter_normal_mode (const char *config);
 void grub_normal_execute (const char *config, int nested);
-void grub_menu_run (grub_menu_t menu, int nested);
+void grub_menu_execute_with_fallback (grub_menu_t menu,
+                                      grub_menu_entry_t entry,
+                                      grub_menu_execute_callback_t callback,
+                                      void *callback_data);
 void grub_menu_entry_run (grub_menu_entry_t entry);
+int grub_menu_get_default_entry_index (grub_menu_t menu);
+int grub_menu_get_timeout (void);
+void grub_menu_set_timeout (int timeout);
+void grub_menu_execute_entry(grub_menu_entry_t entry);
 void grub_cmdline_run (int nested);
 int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
 		      int echo_char, int readline);

=== added file 'include/grub/stringutil.h'
--- include/grub/stringutil.h	1970-01-01 00:00:00 +0000
+++ include/grub/stringutil.h	2008-07-25 15:52:57 +0000
@@ -0,0 +1,32 @@
+/* gfxmenu_stringutil.h - String utilities for the graphical menu interface. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_GFXMENU_STRINGUTIL_HEADER
+#define GRUB_GFXMENU_STRINGUTIL_HEADER 1
+
+#include <grub/types.h>
+
+char *grub_new_substring (const char *buf,
+                          grub_size_t start, grub_size_t end);
+
+char *grub_resolve_relative_path (const char *base, const char *path);
+
+char *grub_get_dirname (const char *file_path);
+
+#endif /* GRUB_GFXMENU_STRINGUTIL_HEADER */

=== modified file 'include/grub/time.h'
--- include/grub/time.h	2007-10-22 19:02:16 +0000
+++ include/grub/time.h	2008-07-28 16:51:30 +0000
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2007, 2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -19,12 +19,15 @@
 #ifndef KERNEL_TIME_HEADER
 #define KERNEL_TIME_HEADER	1
 
+#include <grub/types.h>
 #include <grub/symbol.h>
 #include <grub/machine/time.h>
 #include <grub/cpu/time.h>
 
 void EXPORT_FUNC(grub_millisleep) (grub_uint32_t ms);
-void EXPORT_FUNC(grub_millisleep_generic) (grub_uint32_t ms);
+grub_uint64_t EXPORT_FUNC(grub_get_time_ms) (void);
+
+grub_uint64_t grub_rtc_get_time_ms (void);
 
 static __inline void
 grub_sleep (grub_uint32_t s)
@@ -32,4 +35,6 @@
   grub_millisleep (1000 * s);
 }
 
+void grub_install_get_time_ms (grub_uint64_t (*get_time_ms_func) (void));
+
 #endif /* ! KERNEL_TIME_HEADER */

=== modified file 'include/grub/video.h'
--- include/grub/video.h	2008-01-01 12:02:07 +0000
+++ include/grub/video.h	2008-07-19 19:31:46 +0000
@@ -21,6 +21,7 @@
 
 #include <grub/err.h>
 #include <grub/types.h>
+#include <grub/font.h>
 
 /* Video color in hardware dependent format.  Users should not assume any
    specific coding format.  */
@@ -31,40 +32,41 @@
 struct grub_video_render_target;
 
 /* Forward declarations for used data structures.  */
-struct grub_font_glyph;
 struct grub_video_bitmap;
 
 /* Defines used to describe video mode or rendering target.  */
-#define GRUB_VIDEO_MODE_TYPE_ALPHA		0x00000008
-#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED	0x00000004
+#define GRUB_VIDEO_MODE_TYPE_ALPHA		0x00000020
+#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED	0x00000010
+#define GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP	0x00000004
 #define GRUB_VIDEO_MODE_TYPE_INDEX_COLOR	0x00000002
 #define GRUB_VIDEO_MODE_TYPE_RGB		0x00000001
 
 /* Defines used to mask flags.  */
-#define GRUB_VIDEO_MODE_TYPE_COLOR_MASK		0x00000003
+#define GRUB_VIDEO_MODE_TYPE_COLOR_MASK		0x0000000F
 
 /* Defines used to specify requested bit depth.  */
 #define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK		0x0000ff00
 #define GRUB_VIDEO_MODE_TYPE_DEPTH_POS		8
 
-/* Defined predefined render targets.  */
-#define GRUB_VIDEO_RENDER_TARGET_DISPLAY	((struct grub_video_render_target *) 0)
-#define GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER	((struct grub_video_render_target *) 0)
-#define GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER	((struct grub_video_render_target *) 1)
+/* Predefined render target: */
+/* The render target that client code should render to. */
+#define GRUB_VIDEO_RENDER_TARGET_DISPLAY \
+  ((struct grub_video_render_target *) 0)
+
 
 /* Defined blitting formats.  */
 enum grub_video_blit_format
   {
-    /* Follow exactly field & mask information.  */
-    GRUB_VIDEO_BLIT_FORMAT_RGBA,
-    /* Make optimization assumption.  */
-    GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8,
-    /* Follow exactly field & mask information.  */
-    GRUB_VIDEO_BLIT_FORMAT_RGB,
-    /* Make optimization assumption.  */
-    GRUB_VIDEO_BLIT_FORMAT_R8G8B8,
+    GRUB_VIDEO_BLIT_FORMAT_RGBA,       /* General: Use fields & masks. */
+    GRUB_VIDEO_BLIT_FORMAT_RGBA_8888,  /* Optimized format. */
+    GRUB_VIDEO_BLIT_FORMAT_BGRA_8888,  /* Optimized format. */
+    GRUB_VIDEO_BLIT_FORMAT_RGB,        /* General: Use fields & masks. */
+    GRUB_VIDEO_BLIT_FORMAT_RGB_888,    /* Optimized format. */
+    GRUB_VIDEO_BLIT_FORMAT_BGR_888,    /* Optimized format. */
     /* When needed, decode color or just use value as is.  */
-    GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR
+    GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR,
+    /* Two color bitmap; bits packed: rows are not padded to byte boundary. */
+    GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED
   };
 
 /* Define blitting operators.  */
@@ -127,6 +129,18 @@
   /* What is location of reserved color bits.  In Index Color mode, 
      this is 0.  */
   unsigned int reserved_field_pos;
+
+  /* For 1-bit bitmaps, the background color.  Used for bits = 0. */
+  grub_uint8_t bg_red;
+  grub_uint8_t bg_green;
+  grub_uint8_t bg_blue;
+  grub_uint8_t bg_alpha;
+
+  /* For 1-bit bitmaps, the foreground color.  Used for bits = 1. */
+  grub_uint8_t fg_red;
+  grub_uint8_t fg_green;
+  grub_uint8_t fg_blue;
+  grub_uint8_t fg_alpha;
 };
 
 struct grub_video_palette_data
@@ -137,6 +151,16 @@
   grub_uint8_t a; /* Reserved bits value (0-255).  */
 };
 
+/* A 2D rectangle type.  */
+struct grub_video_rect
+{
+  int x;
+  int y;
+  int width;
+  int height;
+};
+typedef struct grub_video_rect grub_video_rect_t;
+
 struct grub_video_adapter
 {
   /* The video adapter name.  */
@@ -183,6 +207,10 @@
   grub_err_t (*blit_glyph) (struct grub_font_glyph *glyph,
                             grub_video_color_t color, int x, int y);
 
+  grub_err_t (*draw_string) (const char *str, grub_font_t font, 
+                             grub_video_color_t color, 
+                             int left_x, int baseline_y);
+
   grub_err_t (*blit_bitmap) (struct grub_video_bitmap *bitmap,
                              enum grub_video_blit_operators oper,
                              int x, int y, int offset_x, int offset_y,
@@ -255,6 +283,10 @@
 grub_err_t grub_video_blit_glyph (struct grub_font_glyph *glyph,
                                   grub_video_color_t color, int x, int y);
 
+grub_err_t grub_video_draw_string (const char *str, grub_font_t font, 
+                                   grub_video_color_t color, 
+                                   int left_x, int baseline_y);
+
 grub_err_t grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,
                                    enum grub_video_blit_operators oper,
                                    int x, int y, int offset_x, int offset_y,
@@ -269,6 +301,9 @@
 
 grub_err_t grub_video_scroll (grub_video_color_t color, int dx, int dy);
 
+/* Swap the pages referred to by the front buffer and back buffer render
+ * targets, and the page previously referred to by the back buffer is made
+ * visible on the display. */
 grub_err_t grub_video_swap_buffers (void);
 
 grub_err_t grub_video_create_render_target (struct grub_video_render_target **result,
@@ -282,4 +317,21 @@
 
 grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target);
 
+
+/* Defined in video/setmode.c */
+
+/* Set the video mode based on the preferred modes specified in MODE_LIST in
+   the form: <width>x<height>[x<depth>][;...]
+
+   For example:  640x480;800x600x8;400x300x32
+
+   If MODE_LIST is null, or no modes in it are usable, then DEFAULT_WIDTH and
+   DEFAULT_HEIGHT are used to set the mode.  The MODE_FLAGS argument determines
+   the video mode flags such as double buffering that are used.  */
+
+grub_err_t
+grub_video_setup_preferred_mode (const char *mode_list, int mode_flags,
+                                 int default_width, int default_height);
+
+
 #endif /* ! GRUB_VIDEO_HEADER */

=== added directory 'kern/generic'
=== added file 'kern/generic/millisleep.c'
--- kern/generic/millisleep.c	1970-01-01 00:00:00 +0000
+++ kern/generic/millisleep.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,39 @@
+/* millisleep.c - generic millisleep function.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+  grub_uint64_t start;
+
+  start = grub_get_time_ms ();
+
+  /* Instead of setting an end time and looping while the current time is 
+     less than that, comparing the elapsed sleep time with the desired sleep
+     time handles the (unlikely!) case that the timer would wrap around 
+     during the sleep. */
+
+  while (grub_get_time_ms () - start < ms)
+    grub_cpu_idle ();
+}

=== added file 'kern/generic/rtc_get_time_ms.c'
--- kern/generic/rtc_get_time_ms.c	1970-01-01 00:00:00 +0000
+++ kern/generic/rtc_get_time_ms.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,37 @@
+/* rtc_get_time_ms.c - get_time_ms implementation using platform RTC.
+ * The generic implementation of these functions can be used for architectures
+ * or platforms that do not have a more specialized implementation. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+#include <grub/misc.h>
+
+/* Calculate the time in milliseconds since the epoch based on the RTC. */
+grub_uint64_t
+grub_rtc_get_time_ms (void)
+{
+  /* By dimensional analysis: 
+    
+      1000 ms   N rtc ticks       1 s
+      ------- * ----------- * ----------- = 1000*N/T ms
+        1 s          1        T rtc ticks
+   */
+  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
+  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
+}

=== modified file 'kern/i386/efi/init.c'
--- kern/i386/efi/init.c	2007-10-22 18:59:33 +0000
+++ kern/i386/efi/init.c	2008-07-28 16:23:46 +0000
@@ -25,18 +25,13 @@
 #include <grub/cache.h>
 #include <grub/kernel.h>
 #include <grub/efi/efi.h>
-#include <grub/time.h>
-
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
+#include <grub/cpu/tsc.h>
 
 void
 grub_machine_init (void)
 {
   grub_efi_init ();
+  grub_tsc_init ();
 }
 
 void

=== modified file 'kern/i386/linuxbios/init.c'
--- kern/i386/linuxbios/init.c	2008-07-31 18:33:23 +0000
+++ kern/i386/linuxbios/init.c	2008-08-03 03:57:46 +0000
@@ -143,6 +143,8 @@
 
   /* This variable indicates size, not offset.  */
   grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
+
+  grub_install_get_time_ms (grub_rtc_get_time_ms);
 }
 
 void

=== modified file 'kern/i386/pc/init.c'
--- kern/i386/pc/init.c	2008-08-02 22:24:34 +0000
+++ kern/i386/pc/init.c	2008-08-03 03:57:46 +0000
@@ -30,6 +30,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 #include <grub/time.h>
+#include <grub/cpu/tsc.h>
 
 struct mem_region
 {
@@ -46,12 +47,6 @@
 grub_size_t grub_os_area_size;
 grub_size_t grub_lower_mem, grub_upper_mem;
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
 		       grub_size_t len __attribute__ ((unused)))
@@ -231,6 +226,8 @@
   
   if (! grub_os_area_addr)
     grub_fatal ("no upper memory");
+
+  grub_tsc_init ();
 }
 
 void

=== added file 'kern/i386/tsc.c'
--- kern/i386/tsc.c	1970-01-01 00:00:00 +0000
+++ kern/i386/tsc.c	2008-07-28 16:51:30 +0000
@@ -0,0 +1,102 @@
+/* kern/i386/tsc.c - x86 TSC time source implementation
+ * Requires Pentium or better x86 CPU that supports the RDTSC instruction.
+ * This module uses the RTC (via grub_get_rtc()) to calibrate the TSC to 
+ * real time.
+ *
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/time.h>
+#include <grub/misc.h>
+#include <grub/i386/tsc.h>
+
+/* Calibrated reference for TSC=0.  This defines the time since the epoch in 
+   milliseconds that TSC=0 refers to. */
+static grub_uint64_t tsc_boot_time;
+
+/* Calibrated TSC rate.  (In TSC ticks per millisecond.) */
+static grub_uint64_t tsc_ticks_per_ms;
+
+
+grub_uint64_t
+grub_tsc_get_time_ms (void)
+{
+  return tsc_boot_time + grub_divmod64 (grub_get_tsc (), tsc_ticks_per_ms, 0);
+}
+
+
+/* How many RTC ticks to use for calibration loop. (>= 1) */
+#define CALIBRATION_TICKS 2
+
+/* Calibrate the TSC based on the RTC.  */
+static void
+calibrate_tsc (void)
+{
+  /* First calbrate the TSC rate (relative, not absolute time). */
+  grub_uint64_t start_tsc;
+  grub_uint64_t end_tsc;
+  grub_uint32_t initial_tick;
+  grub_uint32_t start_tick;
+  grub_uint32_t end_tick;
+
+  /* Wait for the start of the next tick;
+     we'll base out timing off this edge. */
+  initial_tick = grub_get_rtc ();
+  do
+    {
+      start_tick = grub_get_rtc ();
+    }
+  while (start_tick == initial_tick);
+  start_tsc = grub_get_tsc ();
+
+  /* Wait for the start of the next tick.  This will
+     be the end of the 1-tick period. */
+  do
+    {
+      end_tick = grub_get_rtc ();
+    }
+  while (end_tick - start_tick < CALIBRATION_TICKS);
+  end_tsc = grub_get_tsc ();
+
+  tsc_ticks_per_ms =
+    grub_divmod64 (grub_divmod64
+                   (end_tsc - start_tsc, end_tick - start_tick, 0)
+                   * GRUB_TICKS_PER_SECOND, 1000, 0);
+
+  /* Reference the TSC zero (boot time) to the epoch to 
+     get an absolute real time reference. */
+  grub_uint64_t ms_since_boot = grub_divmod64 (end_tsc, tsc_ticks_per_ms, 0);
+  grub_uint64_t mstime_now = grub_divmod64 ((grub_uint64_t) 1000 * end_tick,
+                                            GRUB_TICKS_PER_SECOND,
+                                            0);
+  tsc_boot_time = mstime_now - ms_since_boot;
+}
+
+void
+grub_tsc_init (void)
+{
+  if (grub_cpu_is_tsc_supported ())
+    {
+      calibrate_tsc ();
+      grub_install_get_time_ms (grub_tsc_get_time_ms);
+    }
+  else
+    {
+      grub_install_get_time_ms (grub_rtc_get_time_ms);
+    }
+}

=== modified file 'kern/ieee1275/init.c'
--- kern/ieee1275/init.c	2008-07-30 09:42:11 +0000
+++ kern/ieee1275/init.c	2008-08-03 03:57:46 +0000
@@ -47,12 +47,6 @@
 extern char _end[];
 
 void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
-void
 grub_exit (void)
 {
   grub_ieee1275_exit ();
@@ -209,6 +203,8 @@
 
 #endif
 
+static grub_uint64_t ieee1275_get_time_ms (void);
+
 void
 grub_machine_init (void)
 {
@@ -258,6 +254,8 @@
 	    }
 	}
     }
+
+  grub_install_get_time_ms (ieee1275_get_time_ms);
 }
 
 void
@@ -267,8 +265,8 @@
   grub_console_fini ();
 }
 
-grub_uint32_t
-grub_get_rtc (void)
+static grub_uint64_t
+ieee1275_get_time_ms (void)
 {
   grub_uint32_t msecs = 0;
 
@@ -277,6 +275,12 @@
   return msecs;
 }
 
+grub_uint32_t
+grub_get_rtc (void)
+{
+  return ieee1275_get_time_ms ();
+}
+
 grub_addr_t
 grub_arch_modules_addr (void)
 {

=== added file 'kern/menu_viewer.c'
--- kern/menu_viewer.c	1970-01-01 00:00:00 +0000
+++ kern/menu_viewer.c	2008-07-19 19:07:47 +0000
@@ -0,0 +1,99 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2005,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/menu_viewer.h>
+#include <grub/menu.h>
+
+/* The list of menu viewers.  */
+static grub_menu_viewer_t menu_viewer_list;
+
+static int should_return;
+static int menu_viewer_changed;
+
+void
+grub_menu_viewer_register (grub_menu_viewer_t viewer)
+{
+  viewer->next = menu_viewer_list;
+  menu_viewer_list = viewer;
+}
+
+static grub_menu_viewer_t get_current_menu_viewer (void)
+{
+  const char *selected_name = grub_env_get ("menuviewer");
+
+  /* If none selected, pick the last registered one. */
+  if (selected_name == 0)
+    return menu_viewer_list;
+
+  grub_menu_viewer_t cur;
+  for (cur = menu_viewer_list; cur; cur = cur->next)
+    {
+      if (grub_strcmp (cur->name, selected_name) == 0)
+        return cur;
+    }
+
+  /* Fall back to the first entry (or null).  */
+  return menu_viewer_list;
+}
+
+grub_err_t
+grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
+{
+  grub_err_t err;
+  int repeat = 0;
+  do
+    {
+      repeat = 0;
+      menu_viewer_changed = 0;
+      grub_menu_viewer_t cur = get_current_menu_viewer ();
+      if (!cur) 
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
+
+      should_return = 0;
+      err = cur->show_menu (menu, nested);
+      if (menu_viewer_changed)
+        repeat = 1;
+    }
+  while (repeat);
+  return err;
+}
+
+int
+grub_menu_viewer_should_return (void)
+{
+  return should_return;
+}
+
+static char *
+menuviewer_write_hook (struct grub_env_var *var __attribute__ ((unused)),
+                       const char *val)
+{
+  menu_viewer_changed = 1;
+  should_return = 1;
+  return grub_strdup (val);
+}
+
+void
+grub_menu_viewer_init (void)
+{
+  grub_register_variable_hook ("menuviewer", 0, menuviewer_write_hook);
+}
+

=== modified file 'kern/misc.c'
--- kern/misc.c	2008-06-15 23:42:48 +0000
+++ kern/misc.c	2008-08-01 15:27:27 +0000
@@ -23,7 +23,6 @@
 #include <stdarg.h>
 #include <grub/term.h>
 #include <grub/env.h>
-#include <grub/time.h>
 
 void *
 grub_memmove (void *dest, const void *src, grub_size_t n)
@@ -359,6 +358,12 @@
 }
 
 int
+grub_iscntrl (int c)
+{
+  return (c >= 0x00 && c <= 0x1F) || c == 0x7F;
+}
+
+int
 grub_isprint (int c)
 {
   return (c >= ' ' && c <= '~');
@@ -371,6 +376,12 @@
 }
 
 int
+grub_isalnum (int c)
+{
+  return grub_isalpha (c) || grub_isdigit (c);
+}
+
+int
 grub_isdigit (int c)
 {
   return (c >= '0' && c <= '9');
@@ -391,6 +402,41 @@
   return c;
 }
 
+long
+grub_strtol (const char *str, char **end, int base)
+{
+  int negative = 0;
+
+  while (*str && grub_isspace (*str))
+    str++;
+
+  if (*str == '-')
+    {
+      negative = 1;
+      str++;
+    }
+
+  unsigned long long magnitude;
+  magnitude = grub_strtoull (str, end, base);
+  if (negative)
+    {
+      if (magnitude > -((long long) LONG_MIN))
+        {
+          grub_error (GRUB_ERR_OUT_OF_RANGE, "negative overflow");
+          return LONG_MIN;
+        }
+      return -((long long) magnitude);
+    }
+  else
+    {
+      if (magnitude > LONG_MAX)
+        {
+          grub_error (GRUB_ERR_OUT_OF_RANGE, "positive overflow");
+          return LONG_MAX;
+        }
+      return (long) magnitude;
+    }
+}
 
 unsigned long
 grub_strtoul (const char *str, char **end, int base)
@@ -1018,17 +1064,6 @@
   return p - dest;
 }
 
-void
-grub_millisleep_generic (grub_uint32_t ms)
-{
-  grub_uint32_t end_at;
-
-  end_at = grub_get_rtc () + grub_div_roundup (ms * GRUB_TICKS_PER_SECOND, 1000);
-
-  while (grub_get_rtc () < end_at)
-    grub_cpu_idle ();
-}
-
 /* Abort GRUB. This function does not return.  */
 void
 grub_abort (void)

=== modified file 'kern/sparc64/ieee1275/init.c'
--- kern/sparc64/ieee1275/init.c	2007-10-22 18:59:33 +0000
+++ kern/sparc64/ieee1275/init.c	2008-07-28 16:23:46 +0000
@@ -66,12 +66,6 @@
   /* Never reached.  */
 }
 
-void
-grub_millisleep (grub_uint32_t ms)
-{
-  grub_millisleep_generic (ms);
-}
-
 int
 grub_ieee1275_test_flag (enum grub_ieee1275_flag flag)
 {
@@ -145,6 +139,8 @@
   grub_free (prefix);
 }
 
+grub_uint64_t ieee1275_get_time_ms (void);
+
 void
 grub_machine_init (void)
 {
@@ -201,6 +197,7 @@
 	}
     }
 
+  grub_install_get_time_ms (ieee1275_get_time_ms);
 }
 
 void
@@ -216,6 +213,12 @@
   grub_ieee1275_enter ();
 }
 
+grub_uint64_t
+ieee1275_get_time_ms (void)
+{
+  return grub_get_rtc ();
+}
+
 grub_uint32_t
 grub_get_rtc (void)
 {

=== added file 'kern/time.c'
--- kern/time.c	1970-01-01 00:00:00 +0000
+++ kern/time.c	2008-07-28 16:23:46 +0000
@@ -0,0 +1,37 @@
+/* time.c - kernel time functions */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/time.h>
+
+typedef grub_uint64_t (*get_time_ms_func_t) (void);
+
+/* Function pointer to the implementation in use.  */
+static get_time_ms_func_t get_time_ms_func;
+
+grub_uint64_t
+grub_get_time_ms (void)
+{
+  return get_time_ms_func ();
+}
+
+void
+grub_install_get_time_ms (get_time_ms_func_t func)
+{
+  get_time_ms_func = func;
+}

=== added file 'lib/luagrub.c'
--- lib/luagrub.c	1970-01-01 00:00:00 +0000
+++ lib/luagrub.c	2008-08-04 17:10:55 +0000
@@ -0,0 +1,185 @@
+/* luagrub.c - Lua GRUB package; provides access to GRUB from Lua.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/time.h>
+#include <grub/bufio.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/term.h>
+#include <grub/bitmap_scale.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include <grub/luagrub.h>
+
+/* Lua function: get_time_ms() : returns the time in milliseconds.  */
+static int
+l_sys_get_time_ms (lua_State *L)
+{
+  lua_pushinteger (L, grub_get_time_ms ());
+  return 1;
+}
+
+
+
+/* Lua function: input.getkey() : returns { ASCII char, scan code }.  */
+static int
+l_input_getkey (lua_State *L)
+{
+  int c = grub_getkey();
+  lua_pushinteger (L, c & 0xFF);          /* Push ASCII character code.  */
+  lua_pushinteger (L, (c >> 8) & 0xFF);   /* Push the scan code.  */
+  return 2;
+}
+
+/* Lua function: input.checkkey() : returns true if a key is waiting.  */
+static int
+l_input_checkkey (lua_State *L)
+{
+  lua_pushboolean (L, grub_checkkey() != -1);
+  return 1;
+}
+
+
+
+/* Lua function: video.set_graphics_mode(). */
+static int
+l_video_set_graphics_mode (lua_State *L)
+{
+  const char *doublebuf_str = grub_env_get ("doublebuffering");
+  int doublebuf_flags =
+    (doublebuf_str && doublebuf_str[0] == 'n')
+    ? 0
+    : GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+
+  const char *modestr = grub_env_get ("gfxmode");
+  if (grub_video_setup_preferred_mode (modestr, doublebuf_flags, 640, 480)
+      != GRUB_ERR_NONE)
+    return luaL_error (L, "Error setting video mode: %s", grub_errmsg);
+
+  return 0;
+}
+
+/* Lua function: video.set_text_mode(). */
+static int 
+l_video_set_text_mode (lua_State *L)
+{
+  if (grub_video_restore () != GRUB_ERR_NONE)
+    return luaL_error (L, "Error setting text mode: %s", grub_errmsg);
+  return 0;
+}
+
+/* Lua function: video.swap_buffers().  */
+static int
+l_video_swap_buffers (lua_State *L)
+{
+  if (grub_video_swap_buffers () != GRUB_ERR_NONE)
+    return luaL_error (L, "Error swapping video buffers: %s", grub_errmsg);
+  return 0;
+}
+
+static grub_video_color_t
+check_grub_color (lua_State *L, int narg)
+{
+  /* Get the color components.  */
+  luaL_argcheck (L, lua_istable (L, narg), narg, "should be a color");
+  lua_getfield (L, narg, "r");
+  lua_getfield (L, narg, "g");
+  lua_getfield (L, narg, "b");
+  lua_getfield (L, narg, "a");
+  grub_video_color_t color;
+  color = grub_video_map_rgba (luaL_checkint (L, -4),
+                               luaL_checkint (L, -3),
+                               luaL_checkint (L, -2),
+                               luaL_optint (L, -1, 255));
+  lua_pop (L, 4);
+  return color;
+}
+
+/* Lua function: video.fill_rect(color, x, y, width, height). */
+static int
+l_video_fill_rect (lua_State *L)
+{
+  grub_video_color_t color = check_grub_color (L, 1);
+  int x = luaL_checkint (L, 2);
+  int y = luaL_checkint (L, 3);
+  int w = luaL_checkint (L, 4);
+  int h = luaL_checkint (L, 5);
+  if (grub_video_fill_rect (color, x, y, w, h) != GRUB_ERR_NONE)
+    return luaL_error (L, "Error filling rectangle: %s", grub_errmsg);
+  return 0;
+}
+
+/* Lua function: video.draw_string(text, font, color, x, y). */
+static int
+l_video_draw_string (lua_State *L)
+{
+  grub_video_draw_string (luaL_checkstring (L, 1),
+                          grub_font_get (luaL_checkstring (L, 2)),
+                          check_grub_color (L, 3),
+                          luaL_checkint (L, 4),
+                          luaL_checkint (L, 5));
+  return 0;
+}
+
+
+static const struct luaL_reg syslib[] = {
+    {"get_time_ms", l_sys_get_time_ms},
+    {0, 0}
+};
+
+static const struct luaL_reg inputlib[] = {
+    {"getkey", l_input_getkey},
+    {"checkkey", l_input_checkkey},
+    {0, 0}
+};
+
+static const struct luaL_reg videolib[] = {
+    {"set_graphics_mode", l_video_set_graphics_mode},
+    {"set_text_mode", l_video_set_text_mode},
+    {"swap_buffers", l_video_swap_buffers},
+    {"fill_rect", l_video_fill_rect},
+    {"draw_string", l_video_draw_string},
+    {0, 0}
+};
+
+int
+grub_lua_load_grub_packages (lua_State *L)
+{
+  luaL_openlib(L, "sys", syslib, 0);
+  luaL_openlib(L, "input", inputlib, 0);
+  luaL_openlib(L, "video", videolib, 0);
+  return 3;  /* 3 items returned on stack: the packages.  */
+}
+
+GRUB_MOD_INIT (luagrub)
+{
+  (void) mod;                   /* To stop warning. */
+}
+
+GRUB_MOD_FINI (luagrub)
+{
+}

=== added directory 'lua'
=== added file 'lua/Makefile'
--- lua/Makefile	1970-01-01 00:00:00 +0000
+++ lua/Makefile	2008-08-01 15:19:23 +0000
@@ -0,0 +1,182 @@
+# makefile for building Lua
+# see ../INSTALL for installation instructions
+# see ../Makefile and luaconf.h for further customization
+
+# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
+
+# Your platform. See PLATS for possible values.
+PLAT= none
+
+CC= gcc
+CFLAGS= -O2 -Wall $(MYCFLAGS)
+AR= ar rcu
+RANLIB= ranlib
+RM= rm -f
+LIBS= -lm $(MYLIBS)
+
+MYCFLAGS=
+MYLDFLAGS=
+MYLIBS=
+
+# == END OF USER SETTINGS. NO NEED TO CHANGE ANYTHING BELOW THIS LINE =========
+
+PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
+
+LUA_A=	liblua.a
+CORE_O=	lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
+	lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \
+	lundump.o lvm.o lzio.o
+LIB_O=	lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
+	lstrlib.o loadlib.o linit.o
+
+LUA_T=	lua
+LUA_O=	lua.o
+
+LUAC_T=	luac
+LUAC_O=	luac.o print.o
+
+ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O)
+ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
+ALL_A= $(LUA_A)
+
+default: $(PLAT)
+
+all:	$(ALL_T)
+
+o:	$(ALL_O)
+
+a:	$(ALL_A)
+
+$(LUA_A): $(CORE_O) $(LIB_O)
+	$(AR) $@ $?
+	$(RANLIB) $@
+
+$(LUA_T): $(LUA_O) $(LUA_A)
+	$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
+
+$(LUAC_T): $(LUAC_O) $(LUA_A)
+	$(CC) -o $@ $(MYLDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
+
+clean:
+	$(RM) $(ALL_T) $(ALL_O)
+
+depend:
+	@$(CC) $(CFLAGS) -MM l*.c print.c
+
+echo:
+	@echo "PLAT = $(PLAT)"
+	@echo "CC = $(CC)"
+	@echo "CFLAGS = $(CFLAGS)"
+	@echo "AR = $(AR)"
+	@echo "RANLIB = $(RANLIB)"
+	@echo "RM = $(RM)"
+	@echo "MYCFLAGS = $(MYCFLAGS)"
+	@echo "MYLDFLAGS = $(MYLDFLAGS)"
+	@echo "MYLIBS = $(MYLIBS)"
+
+# convenience targets for popular platforms
+
+none:
+	@echo "Please choose a platform:"
+	@echo "   $(PLATS)"
+
+aix:
+	$(MAKE) all CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl" MYLDFLAGS="-brtl -bexpall"
+
+ansi:
+	$(MAKE) all MYCFLAGS=-DLUA_ANSI
+
+bsd:
+	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-Wl,-E"
+
+freebsd:
+	$(MAKE) all MYCFLAGS="-DLUA_USE_LINUX" MYLIBS="-Wl,-E -lreadline"
+
+generic:
+	$(MAKE) all MYCFLAGS=
+
+linux:
+	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E -ldl -lreadline -lhistory -lncurses"
+
+macosx:
+	$(MAKE) all MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-lreadline"
+# use this on Mac OS X 10.3-
+#	$(MAKE) all MYCFLAGS=-DLUA_USE_MACOSX
+
+mingw:
+	$(MAKE) "LUA_A=lua51.dll" "LUA_T=lua.exe" \
+	"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
+	"MYCFLAGS=-DLUA_BUILD_AS_DLL" "MYLIBS=" "MYLDFLAGS=-s" lua.exe
+	$(MAKE) "LUAC_T=luac.exe" luac.exe
+
+posix:
+	$(MAKE) all MYCFLAGS=-DLUA_USE_POSIX
+
+solaris:
+	$(MAKE) all MYCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" MYLIBS="-ldl"
+
+# list targets that do not create files (but not all makes understand .PHONY)
+.PHONY: all $(PLATS) default o a clean depend echo none
+
+# DO NOT DELETE
+
+lapi.o: lapi.c lua.h luaconf.h lapi.h lobject.h llimits.h ldebug.h \
+  lstate.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h \
+  lundump.h lvm.h
+lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h
+lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h
+lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
+  lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \
+  ltable.h
+ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
+ldebug.o: ldebug.c lua.h luaconf.h lapi.h lobject.h llimits.h lcode.h \
+  llex.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \
+  lfunc.h lstring.h lgc.h ltable.h lvm.h
+ldo.o: ldo.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
+  lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h lstring.h \
+  ltable.h lundump.h lvm.h
+ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
+  lzio.h lmem.h lundump.h
+lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h lmem.h \
+  lstate.h ltm.h lzio.h
+lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
+  lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
+linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
+liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
+llex.o: llex.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h ltm.h \
+  lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h
+lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
+lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+  ltm.h lzio.h lmem.h ldo.h
+loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
+lobject.o: lobject.c lua.h luaconf.h ldo.h lobject.h llimits.h lstate.h \
+  ltm.h lzio.h lmem.h lstring.h lgc.h lvm.h
+lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h
+loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h
+lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
+  lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h \
+  lfunc.h lstring.h lgc.h ltable.h
+lstate.o: lstate.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+  ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h llex.h lstring.h ltable.h
+lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
+  ltm.h lzio.h lstring.h lgc.h
+lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
+ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
+  ltm.h lzio.h lmem.h ldo.h lgc.h ltable.h
+ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
+ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
+  lmem.h lstring.h lgc.h ltable.h
+lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h
+luac.o: luac.c lua.h luaconf.h lauxlib.h ldo.h lobject.h llimits.h \
+  lstate.h ltm.h lzio.h lmem.h lfunc.h lopcodes.h lstring.h lgc.h \
+  lundump.h
+lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
+  llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h
+lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
+  lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
+lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
+  lzio.h
+print.o: print.c ldebug.h lstate.h lua.h luaconf.h lobject.h llimits.h \
+  ltm.h lzio.h lmem.h lopcodes.h lundump.h
+
+# (end of Makefile)

=== added file 'lua/grublib.h'
--- lua/grublib.h	1970-01-01 00:00:00 +0000
+++ lua/grublib.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,131 @@
+/* grublib.h - Define aliases to the GRUB library functions for Lua. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LUA_GRUBLIB_HEADER
+#define GRUB_LUA_GRUBLIB_HEADER 1
+
+#include <stddef.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+#define isalpha   grub_isalpha
+#define isalnum   grub_isalnum
+#define isdigit   grub_isdigit
+#define isprint   grub_isprint
+#define isspace   grub_isspace
+#define iscntrl   grub_iscntrl
+#define tolower   grub_tolower
+
+static __inline int islower(int c)
+{
+  return c >= 'a' && c <= 'z';
+}
+
+static __inline int isupper(int c)
+{
+  return c >= 'A' && c <= 'Z';
+}
+
+static __inline int toupper(int c)
+{
+  if (islower (c))
+    return (c - 'a') + 'A';
+  return c;
+}
+
+static __inline int isxdigit(int c)
+{
+  return (isdigit (c)
+          || (c >= 'a' && c <= 'f')
+          || (c >= 'A' && c <= 'F'));
+}
+
+static __inline int ispunct(int c)
+{
+  return isprint (c) && !isalnum (c);
+}
+
+
+#define memcmp    grub_memcmp
+#define strcmp    grub_strcmp
+#define strcoll   grub_strcmp
+#define strchr    grub_strchr
+#define strstr    grub_strstr
+#define strcspn   grub_strcspn
+#define strlen    grub_strlen
+#define strcpy    grub_strcpy
+#define strncpy   grub_strncpy
+#define strcat    grub_strcat
+#define strncat   grub_strncat
+
+#define strtol    grub_strtol
+#define strtoul   grub_strtoul
+#define sprintf   grub_sprintf
+#define abs       grub_abs
+
+#define malloc    grub_malloc
+#define realloc   grub_realloc
+#define free      grub_free
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+static __inline void exit (int status __attribute__ ((unused)))
+{
+  grub_exit ();
+}
+
+static __inline void *
+memchr (const char *s, int c, size_t n)
+{
+  while (n)
+    {
+      if (*s == c)
+        return (void *) s;
+
+      n--;
+      s++;
+    }
+  return 0;
+}
+
+static __inline char *
+strpbrk (const char *s, const char *accept)
+{
+  char *p;
+  while (*s)
+    {
+      p = grub_strchr (accept, *s);
+      if (p)
+        return 0;
+
+      s++;
+    }
+  return 0;
+}
+
+static __inline size_t
+strcspn (const char *s, const char *reject)
+{
+  size_t n = 0;
+  while (s[n] && ! grub_strchr (reject, s[n]))
+    n++;
+  return n;
+}
+
+#endif /* ! GRUB_LUA_GRUBLIB_HEADER */

=== added file 'lua/lapi.c'
--- lua/lapi.c	1970-01-01 00:00:00 +0000
+++ lua/lapi.c	2008-08-03 02:57:07 +0000
@@ -0,0 +1,1080 @@
+/*
+** $Id: lapi.c,v 2.55.1.3 2008/01/03 15:20:39 roberto Exp $
+** Lua API
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <assert.h>
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lapi_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+
+
+
+#define api_checknelems(L, n)	api_check(L, (n) <= (L->top - L->base))
+
+#define api_checkvalidindex(L, i)	api_check(L, (i) != luaO_nilobject)
+
+#define api_incr_top(L)   {api_check(L, L->top < L->ci->top); L->top++;}
+
+
+
+static TValue *index2adr (lua_State *L, int idx) {
+  if (idx > 0) {
+    TValue *o = L->base + (idx - 1);
+    api_check(L, idx <= L->ci->top - L->base);
+    if (o >= L->top) return cast(TValue *, luaO_nilobject);
+    else return o;
+  }
+  else if (idx > LUA_REGISTRYINDEX) {
+    api_check(L, idx != 0 && -idx <= L->top - L->base);
+    return L->top + idx;
+  }
+  else switch (idx) {  /* pseudo-indices */
+    case LUA_REGISTRYINDEX: return registry(L);
+    case LUA_ENVIRONINDEX: {
+      Closure *func = curr_func(L);
+      sethvalue(L, &L->env, func->c.env);
+      return &L->env;
+    }
+    case LUA_GLOBALSINDEX: return gt(L);
+    default: {
+      Closure *func = curr_func(L);
+      idx = LUA_GLOBALSINDEX - idx;
+      return (idx <= func->c.nupvalues)
+                ? &func->c.upvalue[idx-1]
+                : cast(TValue *, luaO_nilobject);
+    }
+  }
+}
+
+
+static Table *getcurrenv (lua_State *L) {
+  if (L->ci == L->base_ci)  /* no enclosing function? */
+    return hvalue(gt(L));  /* use global table as environment */
+  else {
+    Closure *func = curr_func(L);
+    return func->c.env;
+  }
+}
+
+
+void luaA_pushobject (lua_State *L, const TValue *o) {
+  setobj2s(L, L->top, o);
+  api_incr_top(L);
+}
+
+
+LUA_API int lua_checkstack (lua_State *L, int size) {
+  int res;
+  lua_lock(L);
+  if ((L->top - L->base + size) > LUAI_MAXCSTACK)
+    res = 0;  /* stack overflow */
+  else {
+    luaD_checkstack(L, size);
+    if (L->ci->top < L->top + size)
+      L->ci->top = L->top + size;
+    res = 1;
+  }
+  lua_unlock(L);
+  return res;
+}
+
+
+LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
+  int i;
+  if (from == to) return;
+  lua_lock(to);
+  api_checknelems(from, n);
+  api_check(from, G(from) == G(to));
+  api_check(from, to->ci->top - to->top >= n);
+  from->top -= n;
+  for (i = 0; i < n; i++) {
+    setobj2s(to, to->top++, from->top + i);
+  }
+  lua_unlock(to);
+}
+
+
+LUA_API void lua_setlevel (lua_State *from, lua_State *to) {
+  to->nCcalls = from->nCcalls;
+}
+
+
+LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
+  lua_CFunction old;
+  lua_lock(L);
+  old = G(L)->panic;
+  G(L)->panic = panicf;
+  lua_unlock(L);
+  return old;
+}
+
+
+LUA_API lua_State *lua_newthread (lua_State *L) {
+  lua_State *L1;
+  lua_lock(L);
+  luaC_checkGC(L);
+  L1 = luaE_newthread(L);
+  setthvalue(L, L->top, L1);
+  api_incr_top(L);
+  lua_unlock(L);
+  luai_userstatethread(L, L1);
+  return L1;
+}
+
+
+
+/*
+** basic stack manipulation
+*/
+
+
+LUA_API int lua_gettop (lua_State *L) {
+  return cast_int(L->top - L->base);
+}
+
+
+LUA_API void lua_settop (lua_State *L, int idx) {
+  lua_lock(L);
+  if (idx >= 0) {
+    api_check(L, idx <= L->stack_last - L->base);
+    while (L->top < L->base + idx)
+      setnilvalue(L->top++);
+    L->top = L->base + idx;
+  }
+  else {
+    api_check(L, -(idx+1) <= (L->top - L->base));
+    L->top += idx+1;  /* `subtract' index (index is negative) */
+  }
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_remove (lua_State *L, int idx) {
+  StkId p;
+  lua_lock(L);
+  p = index2adr(L, idx);
+  api_checkvalidindex(L, p);
+  while (++p < L->top) setobjs2s(L, p-1, p);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_insert (lua_State *L, int idx) {
+  StkId p;
+  StkId q;
+  lua_lock(L);
+  p = index2adr(L, idx);
+  api_checkvalidindex(L, p);
+  for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
+  setobjs2s(L, p, L->top);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_replace (lua_State *L, int idx) {
+  StkId o;
+  lua_lock(L);
+  /* explicit test for incompatible code */
+  if (idx == LUA_ENVIRONINDEX && L->ci == L->base_ci)
+    luaG_runerror(L, "no calling environment");
+  api_checknelems(L, 1);
+  o = index2adr(L, idx);
+  api_checkvalidindex(L, o);
+  if (idx == LUA_ENVIRONINDEX) {
+    Closure *func = curr_func(L);
+    api_check(L, ttistable(L->top - 1)); 
+    func->c.env = hvalue(L->top - 1);
+    luaC_barrier(L, func, L->top - 1);
+  }
+  else {
+    setobj(L, o, L->top - 1);
+    if (idx < LUA_GLOBALSINDEX)  /* function upvalue? */
+      luaC_barrier(L, curr_func(L), L->top - 1);
+  }
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushvalue (lua_State *L, int idx) {
+  lua_lock(L);
+  setobj2s(L, L->top, index2adr(L, idx));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+
+/*
+** access functions (stack -> C)
+*/
+
+
+LUA_API int lua_type (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  return (o == luaO_nilobject) ? LUA_TNONE : ttype(o);
+}
+
+
+LUA_API const char *lua_typename (lua_State *L, int t) {
+  UNUSED(L);
+  return (t == LUA_TNONE) ? "no value" : luaT_typenames[t];
+}
+
+
+LUA_API int lua_iscfunction (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  return iscfunction(o);
+}
+
+
+LUA_API int lua_isnumber (lua_State *L, int idx) {
+  TValue n;
+  const TValue *o = index2adr(L, idx);
+  return tonumber(o, &n);
+}
+
+
+LUA_API int lua_isstring (lua_State *L, int idx) {
+  int t = lua_type(L, idx);
+  return (t == LUA_TSTRING || t == LUA_TNUMBER);
+}
+
+
+LUA_API int lua_isuserdata (lua_State *L, int idx) {
+  const TValue *o = index2adr(L, idx);
+  return (ttisuserdata(o) || ttislightuserdata(o));
+}
+
+
+LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
+  StkId o1 = index2adr(L, index1);
+  StkId o2 = index2adr(L, index2);
+  return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
+         : luaO_rawequalObj(o1, o2);
+}
+
+
+LUA_API int lua_equal (lua_State *L, int index1, int index2) {
+  StkId o1, o2;
+  int i;
+  lua_lock(L);  /* may call tag method */
+  o1 = index2adr(L, index1);
+  o2 = index2adr(L, index2);
+  i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2);
+  lua_unlock(L);
+  return i;
+}
+
+
+LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
+  StkId o1, o2;
+  int i;
+  lua_lock(L);  /* may call tag method */
+  o1 = index2adr(L, index1);
+  o2 = index2adr(L, index2);
+  i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
+       : luaV_lessthan(L, o1, o2);
+  lua_unlock(L);
+  return i;
+}
+
+
+
+LUA_API lua_Number lua_tonumber (lua_State *L, int idx) {
+  TValue n;
+  const TValue *o = index2adr(L, idx);
+  if (tonumber(o, &n))
+    return nvalue(o);
+  else
+    return 0;
+}
+
+
+LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) {
+  TValue n;
+  const TValue *o = index2adr(L, idx);
+  if (tonumber(o, &n)) {
+    lua_Integer res;
+    lua_Number num = nvalue(o);
+    lua_number2integer(res, num);
+    return res;
+  }
+  else
+    return 0;
+}
+
+
+LUA_API int lua_toboolean (lua_State *L, int idx) {
+  const TValue *o = index2adr(L, idx);
+  return !l_isfalse(o);
+}
+
+
+LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
+  StkId o = index2adr(L, idx);
+  if (!ttisstring(o)) {
+    lua_lock(L);  /* `luaV_tostring' may create a new string */
+    if (!luaV_tostring(L, o)) {  /* conversion failed? */
+      if (len != NULL) *len = 0;
+      lua_unlock(L);
+      return NULL;
+    }
+    luaC_checkGC(L);
+    o = index2adr(L, idx);  /* previous call may reallocate the stack */
+    lua_unlock(L);
+  }
+  if (len != NULL) *len = tsvalue(o)->len;
+  return svalue(o);
+}
+
+
+LUA_API size_t lua_objlen (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  switch (ttype(o)) {
+    case LUA_TSTRING: return tsvalue(o)->len;
+    case LUA_TUSERDATA: return uvalue(o)->len;
+    case LUA_TTABLE: return luaH_getn(hvalue(o));
+    case LUA_TNUMBER: {
+      size_t l;
+      lua_lock(L);  /* `luaV_tostring' may create a new string */
+      l = (luaV_tostring(L, o) ? tsvalue(o)->len : 0);
+      lua_unlock(L);
+      return l;
+    }
+    default: return 0;
+  }
+}
+
+
+LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  return (!iscfunction(o)) ? NULL : clvalue(o)->c.f;
+}
+
+
+LUA_API void *lua_touserdata (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  switch (ttype(o)) {
+    case LUA_TUSERDATA: return (rawuvalue(o) + 1);
+    case LUA_TLIGHTUSERDATA: return pvalue(o);
+    default: return NULL;
+  }
+}
+
+
+LUA_API lua_State *lua_tothread (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  return (!ttisthread(o)) ? NULL : thvalue(o);
+}
+
+
+LUA_API const void *lua_topointer (lua_State *L, int idx) {
+  StkId o = index2adr(L, idx);
+  switch (ttype(o)) {
+    case LUA_TTABLE: return hvalue(o);
+    case LUA_TFUNCTION: return clvalue(o);
+    case LUA_TTHREAD: return thvalue(o);
+    case LUA_TUSERDATA:
+    case LUA_TLIGHTUSERDATA:
+      return lua_touserdata(L, idx);
+    default: return NULL;
+  }
+}
+
+
+
+/*
+** push functions (C -> stack)
+*/
+
+
+LUA_API void lua_pushnil (lua_State *L) {
+  lua_lock(L);
+  setnilvalue(L->top);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
+  lua_lock(L);
+  setnvalue(L->top, n);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
+  lua_lock(L);
+  setnvalue(L->top, cast_num(n));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) {
+  lua_lock(L);
+  luaC_checkGC(L);
+  setsvalue2s(L, L->top, luaS_newlstr(L, s, len));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushstring (lua_State *L, const char *s) {
+  if (s == NULL)
+    lua_pushnil(L);
+  else
+    lua_pushlstring(L, s, strlen(s));
+}
+
+
+LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
+                                      va_list argp) {
+  const char *ret;
+  lua_lock(L);
+  luaC_checkGC(L);
+  ret = luaO_pushvfstring(L, fmt, argp);
+  lua_unlock(L);
+  return ret;
+}
+
+
+LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
+  const char *ret;
+  va_list argp;
+  lua_lock(L);
+  luaC_checkGC(L);
+  va_start(argp, fmt);
+  ret = luaO_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  lua_unlock(L);
+  return ret;
+}
+
+
+LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
+  Closure *cl;
+  lua_lock(L);
+  luaC_checkGC(L);
+  api_checknelems(L, n);
+  cl = luaF_newCclosure(L, n, getcurrenv(L));
+  cl->c.f = fn;
+  L->top -= n;
+  while (n--)
+    setobj2n(L, &cl->c.upvalue[n], L->top+n);
+  setclvalue(L, L->top, cl);
+  lua_assert(iswhite(obj2gco(cl)));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushboolean (lua_State *L, int b) {
+  lua_lock(L);
+  setbvalue(L->top, (b != 0));  /* ensure that true is 1 */
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
+  lua_lock(L);
+  setpvalue(L->top, p);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_pushthread (lua_State *L) {
+  lua_lock(L);
+  setthvalue(L, L->top, L);
+  api_incr_top(L);
+  lua_unlock(L);
+  return (G(L)->mainthread == L);
+}
+
+
+
+/*
+** get functions (Lua -> stack)
+*/
+
+
+LUA_API void lua_gettable (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  t = index2adr(L, idx);
+  api_checkvalidindex(L, t);
+  luaV_gettable(L, t, L->top - 1, L->top - 1);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
+  StkId t;
+  TValue key;
+  lua_lock(L);
+  t = index2adr(L, idx);
+  api_checkvalidindex(L, t);
+  setsvalue(L, &key, luaS_new(L, k));
+  luaV_gettable(L, t, &key, L->top);
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawget (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  t = index2adr(L, idx);
+  api_check(L, ttistable(t));
+  setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawgeti (lua_State *L, int idx, int n) {
+  StkId o;
+  lua_lock(L);
+  o = index2adr(L, idx);
+  api_check(L, ttistable(o));
+  setobj2s(L, L->top, luaH_getnum(hvalue(o), n));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
+  lua_lock(L);
+  luaC_checkGC(L);
+  sethvalue(L, L->top, luaH_new(L, narray, nrec));
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_getmetatable (lua_State *L, int objindex) {
+  const TValue *obj;
+  Table *mt = NULL;
+  int res;
+  lua_lock(L);
+  obj = index2adr(L, objindex);
+  switch (ttype(obj)) {
+    case LUA_TTABLE:
+      mt = hvalue(obj)->metatable;
+      break;
+    case LUA_TUSERDATA:
+      mt = uvalue(obj)->metatable;
+      break;
+    default:
+      mt = G(L)->mt[ttype(obj)];
+      break;
+  }
+  if (mt == NULL)
+    res = 0;
+  else {
+    sethvalue(L, L->top, mt);
+    api_incr_top(L);
+    res = 1;
+  }
+  lua_unlock(L);
+  return res;
+}
+
+
+LUA_API void lua_getfenv (lua_State *L, int idx) {
+  StkId o;
+  lua_lock(L);
+  o = index2adr(L, idx);
+  api_checkvalidindex(L, o);
+  switch (ttype(o)) {
+    case LUA_TFUNCTION:
+      sethvalue(L, L->top, clvalue(o)->c.env);
+      break;
+    case LUA_TUSERDATA:
+      sethvalue(L, L->top, uvalue(o)->env);
+      break;
+    case LUA_TTHREAD:
+      setobj2s(L, L->top,  gt(thvalue(o)));
+      break;
+    default:
+      setnilvalue(L->top);
+      break;
+  }
+  api_incr_top(L);
+  lua_unlock(L);
+}
+
+
+/*
+** set functions (stack -> Lua)
+*/
+
+
+LUA_API void lua_settable (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 2);
+  t = index2adr(L, idx);
+  api_checkvalidindex(L, t);
+  luaV_settable(L, t, L->top - 2, L->top - 1);
+  L->top -= 2;  /* pop index and value */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
+  StkId t;
+  TValue key;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  t = index2adr(L, idx);
+  api_checkvalidindex(L, t);
+  setsvalue(L, &key, luaS_new(L, k));
+  luaV_settable(L, t, &key, L->top - 1);
+  L->top--;  /* pop value */
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawset (lua_State *L, int idx) {
+  StkId t;
+  lua_lock(L);
+  api_checknelems(L, 2);
+  t = index2adr(L, idx);
+  api_check(L, ttistable(t));
+  setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1);
+  luaC_barriert(L, hvalue(t), L->top-1);
+  L->top -= 2;
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_rawseti (lua_State *L, int idx, int n) {
+  StkId o;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = index2adr(L, idx);
+  api_check(L, ttistable(o));
+  setobj2t(L, luaH_setnum(L, hvalue(o), n), L->top-1);
+  luaC_barriert(L, hvalue(o), L->top-1);
+  L->top--;
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_setmetatable (lua_State *L, int objindex) {
+  TValue *obj;
+  Table *mt;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  obj = index2adr(L, objindex);
+  api_checkvalidindex(L, obj);
+  if (ttisnil(L->top - 1))
+    mt = NULL;
+  else {
+    api_check(L, ttistable(L->top - 1));
+    mt = hvalue(L->top - 1);
+  }
+  switch (ttype(obj)) {
+    case LUA_TTABLE: {
+      hvalue(obj)->metatable = mt;
+      if (mt)
+        luaC_objbarriert(L, hvalue(obj), mt);
+      break;
+    }
+    case LUA_TUSERDATA: {
+      uvalue(obj)->metatable = mt;
+      if (mt)
+        luaC_objbarrier(L, rawuvalue(obj), mt);
+      break;
+    }
+    default: {
+      G(L)->mt[ttype(obj)] = mt;
+      break;
+    }
+  }
+  L->top--;
+  lua_unlock(L);
+  return 1;
+}
+
+
+LUA_API int lua_setfenv (lua_State *L, int idx) {
+  StkId o;
+  int res = 1;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = index2adr(L, idx);
+  api_checkvalidindex(L, o);
+  api_check(L, ttistable(L->top - 1));
+  switch (ttype(o)) {
+    case LUA_TFUNCTION:
+      clvalue(o)->c.env = hvalue(L->top - 1);
+      break;
+    case LUA_TUSERDATA:
+      uvalue(o)->env = hvalue(L->top - 1);
+      break;
+    case LUA_TTHREAD:
+      sethvalue(L, gt(thvalue(o)), hvalue(L->top - 1));
+      break;
+    default:
+      res = 0;
+      break;
+  }
+  if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
+  L->top--;
+  lua_unlock(L);
+  return res;
+}
+
+
+/*
+** `load' and `call' functions (run Lua code)
+*/
+
+
+#define adjustresults(L,nres) \
+    { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; }
+
+
+#define checkresults(L,na,nr) \
+     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))
+	
+
+LUA_API void lua_call (lua_State *L, int nargs, int nresults) {
+  StkId func;
+  lua_lock(L);
+  api_checknelems(L, nargs+1);
+  checkresults(L, nargs, nresults);
+  func = L->top - (nargs+1);
+  luaD_call(L, func, nresults);
+  adjustresults(L, nresults);
+  lua_unlock(L);
+}
+
+
+
+/*
+** Execute a protected call.
+*/
+struct CallS {  /* data to `f_call' */
+  StkId func;
+  int nresults;
+};
+
+
+static void f_call (lua_State *L, void *ud) {
+  struct CallS *c = cast(struct CallS *, ud);
+  luaD_call(L, c->func, c->nresults);
+}
+
+
+
+LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
+  struct CallS c;
+  int status;
+  ptrdiff_t func;
+  lua_lock(L);
+  api_checknelems(L, nargs+1);
+  checkresults(L, nargs, nresults);
+  if (errfunc == 0)
+    func = 0;
+  else {
+    StkId o = index2adr(L, errfunc);
+    api_checkvalidindex(L, o);
+    func = savestack(L, o);
+  }
+  c.func = L->top - (nargs+1);  /* function to be called */
+  c.nresults = nresults;
+  status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
+  adjustresults(L, nresults);
+  lua_unlock(L);
+  return status;
+}
+
+
+/*
+** Execute a protected C call.
+*/
+struct CCallS {  /* data to `f_Ccall' */
+  lua_CFunction func;
+  void *ud;
+};
+
+
+static void f_Ccall (lua_State *L, void *ud) {
+  struct CCallS *c = cast(struct CCallS *, ud);
+  Closure *cl;
+  cl = luaF_newCclosure(L, 0, getcurrenv(L));
+  cl->c.f = c->func;
+  setclvalue(L, L->top, cl);  /* push function */
+  api_incr_top(L);
+  setpvalue(L->top, c->ud);  /* push only argument */
+  api_incr_top(L);
+  luaD_call(L, L->top - 2, 0);
+}
+
+
+LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud) {
+  struct CCallS c;
+  int status;
+  lua_lock(L);
+  c.func = func;
+  c.ud = ud;
+  status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0);
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
+                      const char *chunkname) {
+  ZIO z;
+  int status;
+  lua_lock(L);
+  if (!chunkname) chunkname = "?";
+  luaZ_init(L, &z, reader, data);
+  status = luaD_protectedparser(L, &z, chunkname);
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
+  int status;
+  TValue *o;
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = L->top - 1;
+  if (isLfunction(o))
+    status = luaU_dump(L, clvalue(o)->l.p, writer, data, 0);
+  else
+    status = 1;
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int  lua_status (lua_State *L) {
+  return L->status;
+}
+
+
+/*
+** Garbage-collection function
+*/
+
+LUA_API int lua_gc (lua_State *L, int what, int data) {
+  int res = 0;
+  global_State *g;
+  lua_lock(L);
+  g = G(L);
+  switch (what) {
+    case LUA_GCSTOP: {
+      g->GCthreshold = MAX_LUMEM;
+      break;
+    }
+    case LUA_GCRESTART: {
+      g->GCthreshold = g->totalbytes;
+      break;
+    }
+    case LUA_GCCOLLECT: {
+      luaC_fullgc(L);
+      break;
+    }
+    case LUA_GCCOUNT: {
+      /* GC values are expressed in Kbytes: #bytes/2^10 */
+      res = cast_int(g->totalbytes >> 10);
+      break;
+    }
+    case LUA_GCCOUNTB: {
+      res = cast_int(g->totalbytes & 0x3ff);
+      break;
+    }
+    case LUA_GCSTEP: {
+      lu_mem a = (cast(lu_mem, data) << 10);
+      if (a <= g->totalbytes)
+        g->GCthreshold = g->totalbytes - a;
+      else
+        g->GCthreshold = 0;
+      while (g->GCthreshold <= g->totalbytes)
+        luaC_step(L);
+      if (g->gcstate == GCSpause)  /* end of cycle? */
+        res = 1;  /* signal it */
+      break;
+    }
+    case LUA_GCSETPAUSE: {
+      res = g->gcpause;
+      g->gcpause = data;
+      break;
+    }
+    case LUA_GCSETSTEPMUL: {
+      res = g->gcstepmul;
+      g->gcstepmul = data;
+      break;
+    }
+    default: res = -1;  /* invalid option */
+  }
+  lua_unlock(L);
+  return res;
+}
+
+
+
+/*
+** miscellaneous functions
+*/
+
+
+LUA_API int lua_error (lua_State *L) {
+  lua_lock(L);
+  api_checknelems(L, 1);
+  luaG_errormsg(L);
+  lua_unlock(L);
+  return 0;  /* to avoid warnings */
+}
+
+
+LUA_API int lua_next (lua_State *L, int idx) {
+  StkId t;
+  int more;
+  lua_lock(L);
+  t = index2adr(L, idx);
+  api_check(L, ttistable(t));
+  more = luaH_next(L, hvalue(t), L->top - 1);
+  if (more) {
+    api_incr_top(L);
+  }
+  else  /* no more elements */
+    L->top -= 1;  /* remove key */
+  lua_unlock(L);
+  return more;
+}
+
+
+LUA_API void lua_concat (lua_State *L, int n) {
+  lua_lock(L);
+  api_checknelems(L, n);
+  if (n >= 2) {
+    luaC_checkGC(L);
+    luaV_concat(L, n, cast_int(L->top - L->base) - 1);
+    L->top -= (n-1);
+  }
+  else if (n == 0) {  /* push empty string */
+    setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
+    api_incr_top(L);
+  }
+  /* else n == 1; nothing to do */
+  lua_unlock(L);
+}
+
+
+LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) {
+  lua_Alloc f;
+  lua_lock(L);
+  if (ud) *ud = G(L)->ud;
+  f = G(L)->frealloc;
+  lua_unlock(L);
+  return f;
+}
+
+
+LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
+  lua_lock(L);
+  G(L)->ud = ud;
+  G(L)->frealloc = f;
+  lua_unlock(L);
+}
+
+
+LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
+  Udata *u;
+  lua_lock(L);
+  luaC_checkGC(L);
+  u = luaS_newudata(L, size, getcurrenv(L));
+  setuvalue(L, L->top, u);
+  api_incr_top(L);
+  lua_unlock(L);
+  return u + 1;
+}
+
+
+
+
+static const char *aux_upvalue (StkId fi, int n, TValue **val) {
+  Closure *f;
+  if (!ttisfunction(fi)) return NULL;
+  f = clvalue(fi);
+  if (f->c.isC) {
+    if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
+    *val = &f->c.upvalue[n-1];
+    return "";
+  }
+  else {
+    Proto *p = f->l.p;
+    if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
+    *val = f->l.upvals[n-1]->v;
+    return getstr(p->upvalues[n-1]);
+  }
+}
+
+
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
+  const char *name;
+  TValue *val;
+  lua_lock(L);
+  name = aux_upvalue(index2adr(L, funcindex), n, &val);
+  if (name) {
+    setobj2s(L, L->top, val);
+    api_incr_top(L);
+  }
+  lua_unlock(L);
+  return name;
+}
+
+
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
+  const char *name;
+  TValue *val;
+  StkId fi;
+  lua_lock(L);
+  fi = index2adr(L, funcindex);
+  api_checknelems(L, 1);
+  name = aux_upvalue(fi, n, &val);
+  if (name) {
+    L->top--;
+    setobj(L, val, L->top);
+    luaC_barrier(L, clvalue(fi), L->top);
+  }
+  lua_unlock(L);
+  return name;
+}
+

=== added file 'lua/lapi.h'
--- lua/lapi.h	1970-01-01 00:00:00 +0000
+++ lua/lapi.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,16 @@
+/*
+** $Id: lapi.h,v 2.2.1.1 2007/12/27 13:02:25 roberto Exp $
+** Auxiliary functions from Lua API
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lapi_h
+#define lapi_h
+
+
+#include "lobject.h"
+
+
+LUAI_FUNC void luaA_pushobject (lua_State *L, const TValue *o);
+
+#endif

=== added file 'lua/lauxlib.c'
--- lua/lauxlib.c	1970-01-01 00:00:00 +0000
+++ lua/lauxlib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,679 @@
+/*
+** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#else
+#include <grub/file.h>
+#include <grub/bufio.h>
+#include <grub/err.h>
+#endif /* USE_GRUB_LIB */
+
+
+/* This file uses only the official API of Lua.
+** Any function declared here could be written as an application function.
+*/
+
+#define lauxlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+
+
+#define FREELIST_REF	0	/* free list of references */
+
+
+/* convert a stack index to positive */
+#define abs_index(L, i)		((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
+					lua_gettop(L) + (i) + 1)
+
+
+/*
+** {======================================================
+** Error-report functions
+** =======================================================
+*/
+
+
+LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
+  lua_Debug ar;
+  if (!lua_getstack(L, 0, &ar))  /* no stack frame? */
+    return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
+  lua_getinfo(L, "n", &ar);
+  if (strcmp(ar.namewhat, "method") == 0) {
+    narg--;  /* do not count `self' */
+    if (narg == 0)  /* error is in the self argument itself? */
+      return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
+                           ar.name, extramsg);
+  }
+  if (ar.name == NULL)
+    ar.name = "?";
+  return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
+                        narg, ar.name, extramsg);
+}
+
+
+LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
+  const char *msg = lua_pushfstring(L, "%s expected, got %s",
+                                    tname, luaL_typename(L, narg));
+  return luaL_argerror(L, narg, msg);
+}
+
+
+static void tag_error (lua_State *L, int narg, int tag) {
+  luaL_typerror(L, narg, lua_typename(L, tag));
+}
+
+
+LUALIB_API void luaL_where (lua_State *L, int level) {
+  lua_Debug ar;
+  if (lua_getstack(L, level, &ar)) {  /* check function at level */
+    lua_getinfo(L, "Sl", &ar);  /* get info about it */
+    if (ar.currentline > 0) {  /* is there info? */
+      lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
+      return;
+    }
+  }
+  lua_pushliteral(L, "");  /* else, no information available... */
+}
+
+
+LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
+  va_list argp;
+  va_start(argp, fmt);
+  luaL_where(L, 1);
+  lua_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  lua_concat(L, 2);
+  return lua_error(L);
+}
+
+/* }====================================================== */
+
+
+LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
+                                 const char *const lst[]) {
+  const char *name = (def) ? luaL_optstring(L, narg, def) :
+                             luaL_checkstring(L, narg);
+  int i;
+  for (i=0; lst[i]; i++)
+    if (strcmp(lst[i], name) == 0)
+      return i;
+  return luaL_argerror(L, narg,
+                       lua_pushfstring(L, "invalid option " LUA_QS, name));
+}
+
+
+LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
+  lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get registry.name */
+  if (!lua_isnil(L, -1))  /* name already in use? */
+    return 0;  /* leave previous value on top, but return 0 */
+  lua_pop(L, 1);
+  lua_newtable(L);  /* create metatable */
+  lua_pushvalue(L, -1);
+  lua_setfield(L, LUA_REGISTRYINDEX, tname);  /* registry.name = metatable */
+  return 1;
+}
+
+
+LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
+  void *p = lua_touserdata(L, ud);
+  if (p != NULL) {  /* value is a userdata? */
+    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
+      lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */
+      if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */
+        lua_pop(L, 2);  /* remove both metatables */
+        return p;
+      }
+    }
+  }
+  luaL_typerror(L, ud, tname);  /* else error */
+  return NULL;  /* to avoid warnings */
+}
+
+
+LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
+  if (!lua_checkstack(L, space))
+    luaL_error(L, "stack overflow (%s)", mes);
+}
+
+
+LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
+  if (lua_type(L, narg) != t)
+    tag_error(L, narg, t);
+}
+
+
+LUALIB_API void luaL_checkany (lua_State *L, int narg) {
+  if (lua_type(L, narg) == LUA_TNONE)
+    luaL_argerror(L, narg, "value expected");
+}
+
+
+LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
+  const char *s = lua_tolstring(L, narg, len);
+  if (!s) tag_error(L, narg, LUA_TSTRING);
+  return s;
+}
+
+
+LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
+                                        const char *def, size_t *len) {
+  if (lua_isnoneornil(L, narg)) {
+    if (len)
+      *len = (def ? strlen(def) : 0);
+    return def;
+  }
+  else return luaL_checklstring(L, narg, len);
+}
+
+
+LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
+  lua_Number d = lua_tonumber(L, narg);
+  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
+    tag_error(L, narg, LUA_TNUMBER);
+  return d;
+}
+
+
+LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
+  return luaL_opt(L, luaL_checknumber, narg, def);
+}
+
+
+LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
+  lua_Integer d = lua_tointeger(L, narg);
+  if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
+    tag_error(L, narg, LUA_TNUMBER);
+  return d;
+}
+
+
+LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
+                                                      lua_Integer def) {
+  return luaL_opt(L, luaL_checkinteger, narg, def);
+}
+
+
+LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
+  if (!lua_getmetatable(L, obj))  /* no metatable? */
+    return 0;
+  lua_pushstring(L, event);
+  lua_rawget(L, -2);
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 2);  /* remove metatable and metafield */
+    return 0;
+  }
+  else {
+    lua_remove(L, -2);  /* remove only metatable */
+    return 1;
+  }
+}
+
+
+LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
+  obj = abs_index(L, obj);
+  if (!luaL_getmetafield(L, obj, event))  /* no metafield? */
+    return 0;
+  lua_pushvalue(L, obj);
+  lua_call(L, 1, 1);
+  return 1;
+}
+
+
+LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
+                                const luaL_Reg *l) {
+  luaI_openlib(L, libname, l, 0);
+}
+
+
+static int libsize (const luaL_Reg *l) {
+  int size = 0;
+  for (; l->name; l++) size++;
+  return size;
+}
+
+
+LUALIB_API void luaI_openlib (lua_State *L, const char *libname,
+                              const luaL_Reg *l, int nup) {
+  if (libname) {
+    int size = libsize(l);
+    /* check whether lib already exists */
+    luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
+    lua_getfield(L, -1, libname);  /* get _LOADED[libname] */
+    if (!lua_istable(L, -1)) {  /* not found? */
+      lua_pop(L, 1);  /* remove previous result */
+      /* try global variable (and create one if it does not exist) */
+      if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
+        luaL_error(L, "name conflict for module " LUA_QS, libname);
+      lua_pushvalue(L, -1);
+      lua_setfield(L, -3, libname);  /* _LOADED[libname] = new table */
+    }
+    lua_remove(L, -2);  /* remove _LOADED table */
+    lua_insert(L, -(nup+1));  /* move library table to below upvalues */
+  }
+  for (; l->name; l++) {
+    int i;
+    for (i=0; i<nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -nup);
+    lua_pushcclosure(L, l->func, nup);
+    lua_setfield(L, -(nup+2), l->name);
+  }
+  lua_pop(L, nup);  /* remove upvalues */
+}
+
+
+
+/*
+** {======================================================
+** getn-setn: size for arrays
+** =======================================================
+*/
+
+#if defined(LUA_COMPAT_GETN)
+
+static int checkint (lua_State *L, int topop) {
+  int n = (lua_type(L, -1) == LUA_TNUMBER) ? lua_tointeger(L, -1) : -1;
+  lua_pop(L, topop);
+  return n;
+}
+
+
+static void getsizes (lua_State *L) {
+  lua_getfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");
+  if (lua_isnil(L, -1)) {  /* no `size' table? */
+    lua_pop(L, 1);  /* remove nil */
+    lua_newtable(L);  /* create it */
+    lua_pushvalue(L, -1);  /* `size' will be its own metatable */
+    lua_setmetatable(L, -2);
+    lua_pushliteral(L, "kv");
+    lua_setfield(L, -2, "__mode");  /* metatable(N).__mode = "kv" */
+    lua_pushvalue(L, -1);
+    lua_setfield(L, LUA_REGISTRYINDEX, "LUA_SIZES");  /* store in register */
+  }
+}
+
+
+LUALIB_API void luaL_setn (lua_State *L, int t, int n) {
+  t = abs_index(L, t);
+  lua_pushliteral(L, "n");
+  lua_rawget(L, t);
+  if (checkint(L, 1) >= 0) {  /* is there a numeric field `n'? */
+    lua_pushliteral(L, "n");  /* use it */
+    lua_pushinteger(L, n);
+    lua_rawset(L, t);
+  }
+  else {  /* use `sizes' */
+    getsizes(L);
+    lua_pushvalue(L, t);
+    lua_pushinteger(L, n);
+    lua_rawset(L, -3);  /* sizes[t] = n */
+    lua_pop(L, 1);  /* remove `sizes' */
+  }
+}
+
+
+LUALIB_API int luaL_getn (lua_State *L, int t) {
+  int n;
+  t = abs_index(L, t);
+  lua_pushliteral(L, "n");  /* try t.n */
+  lua_rawget(L, t);
+  if ((n = checkint(L, 1)) >= 0) return n;
+  getsizes(L);  /* else try sizes[t] */
+  lua_pushvalue(L, t);
+  lua_rawget(L, -2);
+  if ((n = checkint(L, 2)) >= 0) return n;
+  return (int)lua_objlen(L, t);
+}
+
+#endif
+
+/* }====================================================== */
+
+
+
+LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
+                                                               const char *r) {
+  const char *wild;
+  size_t l = strlen(p);
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  while ((wild = strstr(s, p)) != NULL) {
+    luaL_addlstring(&b, s, wild - s);  /* push prefix */
+    luaL_addstring(&b, r);  /* push replacement in place of pattern */
+    s = wild + l;  /* continue after `p' */
+  }
+  luaL_addstring(&b, s);  /* push last suffix */
+  luaL_pushresult(&b);
+  return lua_tostring(L, -1);
+}
+
+
+LUALIB_API const char *luaL_findtable (lua_State *L, int idx,
+                                       const char *fname, int szhint) {
+  const char *e;
+  lua_pushvalue(L, idx);
+  do {
+    e = strchr(fname, '.');
+    if (e == NULL) e = fname + strlen(fname);
+    lua_pushlstring(L, fname, e - fname);
+    lua_rawget(L, -2);
+    if (lua_isnil(L, -1)) {  /* no such field? */
+      lua_pop(L, 1);  /* remove this nil */
+      lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
+      lua_pushlstring(L, fname, e - fname);
+      lua_pushvalue(L, -2);
+      lua_settable(L, -4);  /* set new table into field */
+    }
+    else if (!lua_istable(L, -1)) {  /* field has a non-table value? */
+      lua_pop(L, 2);  /* remove table and value */
+      return fname;  /* return problematic part of the name */
+    }
+    lua_remove(L, -2);  /* remove previous table */
+    fname = e + 1;
+  } while (*e == '.');
+  return NULL;
+}
+
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+#define bufflen(B)	((B)->p - (B)->buffer)
+#define bufffree(B)	((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
+
+#define LIMIT	(LUA_MINSTACK/2)
+
+
+static int emptybuffer (luaL_Buffer *B) {
+  size_t l = bufflen(B);
+  if (l == 0) return 0;  /* put nothing on stack */
+  else {
+    lua_pushlstring(B->L, B->buffer, l);
+    B->p = B->buffer;
+    B->lvl++;
+    return 1;
+  }
+}
+
+
+static void adjuststack (luaL_Buffer *B) {
+  if (B->lvl > 1) {
+    lua_State *L = B->L;
+    int toget = 1;  /* number of levels to concat */
+    size_t toplen = lua_strlen(L, -1);
+    do {
+      size_t l = lua_strlen(L, -(toget+1));
+      if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
+        toplen += l;
+        toget++;
+      }
+      else break;
+    } while (toget < B->lvl);
+    lua_concat(L, toget);
+    B->lvl = B->lvl - toget + 1;
+  }
+}
+
+
+LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
+  if (emptybuffer(B))
+    adjuststack(B);
+  return B->buffer;
+}
+
+
+LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
+  while (l--)
+    luaL_addchar(B, *s++);
+}
+
+
+LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
+  luaL_addlstring(B, s, strlen(s));
+}
+
+
+LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
+  emptybuffer(B);
+  lua_concat(B->L, B->lvl);
+  B->lvl = 1;
+}
+
+
+LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
+  lua_State *L = B->L;
+  size_t vl;
+  const char *s = lua_tolstring(L, -1, &vl);
+  if (vl <= bufffree(B)) {  /* fit into buffer? */
+    memcpy(B->p, s, vl);  /* put it there */
+    B->p += vl;
+    lua_pop(L, 1);  /* remove from stack */
+  }
+  else {
+    if (emptybuffer(B))
+      lua_insert(L, -2);  /* put buffer before new value */
+    B->lvl++;  /* add new value into B stack */
+    adjuststack(B);
+  }
+}
+
+
+LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
+  B->L = L;
+  B->p = B->buffer;
+  B->lvl = 0;
+}
+
+/* }====================================================== */
+
+
+LUALIB_API int luaL_ref (lua_State *L, int t) {
+  int ref;
+  t = abs_index(L, t);
+  if (lua_isnil(L, -1)) {
+    lua_pop(L, 1);  /* remove from stack */
+    return LUA_REFNIL;  /* `nil' has a unique fixed reference */
+  }
+  lua_rawgeti(L, t, FREELIST_REF);  /* get first free element */
+  ref = (int)lua_tointeger(L, -1);  /* ref = t[FREELIST_REF] */
+  lua_pop(L, 1);  /* remove it from stack */
+  if (ref != 0) {  /* any free element? */
+    lua_rawgeti(L, t, ref);  /* remove it from list */
+    lua_rawseti(L, t, FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */
+  }
+  else {  /* no free elements */
+    ref = (int)lua_objlen(L, t);
+    ref++;  /* create new reference */
+  }
+  lua_rawseti(L, t, ref);
+  return ref;
+}
+
+
+LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
+  if (ref >= 0) {
+    t = abs_index(L, t);
+    lua_rawgeti(L, t, FREELIST_REF);
+    lua_rawseti(L, t, ref);  /* t[ref] = t[FREELIST_REF] */
+    lua_pushinteger(L, ref);
+    lua_rawseti(L, t, FREELIST_REF);  /* t[FREELIST_REF] = ref */
+  }
+}
+
+
+
+/*
+** {======================================================
+** Load functions
+** =======================================================
+*/
+
+typedef struct LoadF {
+  int extraline;
+  grub_file_t f;
+  char buff[LUAL_BUFFERSIZE];
+} LoadF;
+
+
+#define EOF (-1)
+
+static int grub_file_error_flag = 0;
+
+static int grub_getc(grub_file_t f)
+{
+  char c;
+  if (grub_file_read (f, &c, 1) != 1)
+    {
+      grub_file_error_flag = 1;
+      return EOF;
+    }
+  grub_file_error_flag = 0;
+  return c;
+}
+
+static int grub_ferror(void)
+{
+  return grub_file_error_flag;
+}
+
+
+static const char *getF (lua_State *L, void *ud, size_t *size) {
+  LoadF *lf = (LoadF *)ud;
+  (void)L;
+  if (lf->extraline) {
+    lf->extraline = 0;
+    *size = 1;
+    return "\n";
+  }
+  *size = grub_file_read(lf->f, lf->buff, sizeof(lf->buff));
+  return (*size > 0) ? lf->buff : NULL;
+}
+
+
+static int errfile (lua_State *L, const char *what, int fnameindex) {
+  const char *serr = grub_errmsg;
+  const char *filename = lua_tostring(L, fnameindex) + 1;
+  lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
+  lua_remove(L, fnameindex);
+  return LUA_ERRFILE;
+}
+
+LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
+  LoadF lf;
+  int status, readstatus;
+  int c;
+  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */
+  lf.extraline = 0;
+  if (filename == NULL) {
+    lua_pushliteral(L, "=stdin");
+    grub_error(GRUB_ERR_UNKNOWN_DEVICE, "stdin not supported");
+    return errfile(L, "open stdin (not supported)", fnameindex);
+  }
+  else {
+    lua_pushfstring(L, "@%s", filename);
+    lf.f = grub_buffile_open(filename, -1);
+    if (lf.f == NULL) return errfile(L, "open", fnameindex);
+  }
+  c = grub_getc(lf.f);
+  if (c == '#') {  /* Unix exec. file? */
+    lf.extraline = 1;
+    while ((c = grub_getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */
+    if (c == '\n') c = grub_getc(lf.f);
+  }
+  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
+    grub_file_seek(lf.f, 0);
+    /* skip eventual `#!...' */
+   while ((c = grub_getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
+    lf.extraline = 0;
+  }
+  grub_file_seek(lf.f, 0);
+  status = lua_load(L, getF, &lf, lua_tostring(L, -1));
+  readstatus = grub_ferror();
+  if (filename) grub_file_close(lf.f);  /* close file (even in case of errors) */
+  if (readstatus) {
+    lua_settop(L, fnameindex);  /* ignore results from `lua_load' */
+    return errfile(L, "read", fnameindex);
+  }
+  lua_remove(L, fnameindex);
+  return status;
+}
+
+
+typedef struct LoadS {
+  const char *s;
+  size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+  LoadS *ls = (LoadS *)ud;
+  (void)L;
+  if (ls->size == 0) return NULL;
+  *size = ls->size;
+  ls->size = 0;
+  return ls->s;
+}
+
+
+LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
+                                const char *name) {
+  LoadS ls;
+  ls.s = buff;
+  ls.size = size;
+  return lua_load(L, getS, &ls, name);
+}
+
+
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s) {
+  return luaL_loadbuffer(L, s, strlen(s), s);
+}
+
+
+
+/* }====================================================== */
+
+
+static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
+  (void)ud;
+  (void)osize;
+  if (nsize == 0) {
+    grub_free(ptr);
+    return NULL;
+  }
+  else
+    return grub_realloc(ptr, nsize);
+}
+
+
+static int panic (lua_State *L) {
+  (void)L;  /* to avoid warnings */
+  grub_printf("PANIC: unprotected error in call to Lua API (%s)\n",
+              lua_tostring(L, -1));
+  return 0;
+}
+
+
+LUALIB_API lua_State *luaL_newstate (void) {
+  lua_State *L = lua_newstate(l_alloc, NULL);
+  if (L) lua_atpanic(L, &panic);
+  return L;
+}
+

=== added file 'lua/lauxlib.h'
--- lua/lauxlib.h	1970-01-01 00:00:00 +0000
+++ lua/lauxlib.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,176 @@
+/*
+** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#ifndef USE_GRUB_LIB
+#include <stdio.h>
+#endif /* ! USE_GRUB_LIB */
+
+#include "lua.h"
+
+
+#if defined(LUA_COMPAT_GETN)
+LUALIB_API int (luaL_getn) (lua_State *L, int t);
+LUALIB_API void (luaL_setn) (lua_State *L, int t, int n);
+#else
+#define luaL_getn(L,i)          ((int)lua_objlen(L, i))
+#define luaL_setn(L,i,j)        ((void)0)  /* no op! */
+#endif
+
+#if defined(LUA_COMPAT_OPENLIB)
+#define luaI_openlib	luaL_openlib
+#endif
+
+
+/* extra error code for `luaL_load' */
+#define LUA_ERRFILE     (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+  const char *name;
+  lua_CFunction func;
+} luaL_Reg;
+
+
+
+LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname,
+                                const luaL_Reg *l, int nup);
+LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
+                                const luaL_Reg *l);
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
+LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
+                                                          size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
+                                          const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
+                                          lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
+
+LUALIB_API int   (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
+                                   const char *const lst[]);
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
+LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
+                                  const char *name);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+                                                  const char *r);
+
+LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
+                                         const char *fname, int szhint);
+
+
+
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define luaL_argcheck(L, cond,numarg,extramsg)	\
+		((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
+#define luaL_checkstring(L,n)	(luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d)	(luaL_optlstring(L, (n), (d), NULL))
+#define luaL_checkint(L,n)	((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d)	((int)luaL_optinteger(L, (n), (d)))
+#define luaL_checklong(L,n)	((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d)	((long)luaL_optinteger(L, (n), (d)))
+
+#define luaL_typename(L,i)	lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+	(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+	(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n)	(lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d)	(lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+
+
+typedef struct luaL_Buffer {
+  char *p;			/* current position in buffer */
+  int lvl;  /* number of strings in the stack (level) */
+  lua_State *L;
+  char buffer[LUAL_BUFFERSIZE];
+} luaL_Buffer;
+
+#define luaL_addchar(B,c) \
+  ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
+   (*(B)->p++ = (char)(c)))
+
+/* compatibility only */
+#define luaL_putchar(B,c)	luaL_addchar(B,c)
+
+#define luaL_addsize(B,n)	((B)->p += (n))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+
+
+/* }====================================================== */
+
+
+/* compatibility with ref system */
+
+/* pre-defined references */
+#define LUA_NOREF       (-2)
+#define LUA_REFNIL      (-1)
+
+#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
+      (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
+
+#define lua_unref(L,ref)        luaL_unref(L, LUA_REGISTRYINDEX, (ref))
+
+#define lua_getref(L,ref)       lua_rawgeti(L, LUA_REGISTRYINDEX, (ref))
+
+
+#define luaL_reg	luaL_Reg
+
+#endif
+
+

=== added file 'lua/lbaselib.c'
--- lua/lbaselib.c	1970-01-01 00:00:00 +0000
+++ lua/lbaselib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,656 @@
+/*
+** $Id: lbaselib.c,v 1.191.1.4 2008/01/20 13:53:22 roberto Exp $
+** Basic library
+** See Copyright Notice in lua.h
+*/
+
+
+
+#ifndef USE_GRUB_LIB
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define PRINT(s) fputs(s, stdout)
+#else
+#define PRINT(s) grub_printf("%s", s)
+#endif /* ! USE_GRUB_LIB */
+
+#define lbaselib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+
+/*
+** If your system does not support `stdout', you can just remove this function.
+** If you need, you can define your own `print' function, following this
+** model but changing `fputs' to put the strings at a proper place
+** (a console window or a log file, for instance).
+*/
+static int luaB_print (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  int i;
+  lua_getglobal(L, "tostring");
+  for (i=1; i<=n; i++) {
+    const char *s;
+    lua_pushvalue(L, -1);  /* function to be called */
+    lua_pushvalue(L, i);   /* value to print */
+    lua_call(L, 1, 1);
+    s = lua_tostring(L, -1);  /* get result */
+    if (s == NULL)
+      return luaL_error(L, LUA_QL("tostring") " must return a string to "
+                           LUA_QL("print"));
+    if (i>1) PRINT("\t");
+    PRINT(s);
+    lua_pop(L, 1);  /* pop result */
+  }
+  PRINT("\n");
+  return 0;
+}
+
+
+static int luaB_tonumber (lua_State *L) {
+  int base = luaL_optint(L, 2, 10);
+  if (base == 10) {  /* standard conversion */
+    luaL_checkany(L, 1);
+    if (lua_isnumber(L, 1)) {
+      lua_pushnumber(L, lua_tonumber(L, 1));
+      return 1;
+    }
+  }
+  else {
+    const char *s1 = luaL_checkstring(L, 1);
+    char *s2;
+    unsigned long n;
+    luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+    n = strtoul(s1, &s2, base);
+    if (s1 != s2) {  /* at least one valid digit? */
+      while (isspace((unsigned char)(*s2))) s2++;  /* skip trailing spaces */
+      if (*s2 == '\0') {  /* no invalid trailing characters? */
+        lua_pushnumber(L, (lua_Number)n);
+        return 1;
+      }
+    }
+  }
+  lua_pushnil(L);  /* else not a number */
+  return 1;
+}
+
+
+static int luaB_error (lua_State *L) {
+  int level = luaL_optint(L, 2, 1);
+  lua_settop(L, 1);
+  if (lua_isstring(L, 1) && level > 0) {  /* add extra information? */
+    luaL_where(L, level);
+    lua_pushvalue(L, 1);
+    lua_concat(L, 2);
+  }
+  return lua_error(L);
+}
+
+
+static int luaB_getmetatable (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (!lua_getmetatable(L, 1)) {
+    lua_pushnil(L);
+    return 1;  /* no metatable */
+  }
+  luaL_getmetafield(L, 1, "__metatable");
+  return 1;  /* returns either __metatable field (if present) or metatable */
+}
+
+
+static int luaB_setmetatable (lua_State *L) {
+  int t = lua_type(L, 2);
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+                    "nil or table expected");
+  if (luaL_getmetafield(L, 1, "__metatable"))
+    luaL_error(L, "cannot change a protected metatable");
+  lua_settop(L, 2);
+  lua_setmetatable(L, 1);
+  return 1;
+}
+
+
+static void getfunc (lua_State *L, int opt) {
+  if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
+  else {
+    lua_Debug ar;
+    int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
+    luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
+    if (lua_getstack(L, level, &ar) == 0)
+      luaL_argerror(L, 1, "invalid level");
+    lua_getinfo(L, "f", &ar);
+    if (lua_isnil(L, -1))
+      luaL_error(L, "no function environment for tail call at level %d",
+                    level);
+  }
+}
+
+
+static int luaB_getfenv (lua_State *L) {
+  getfunc(L, 1);
+  if (lua_iscfunction(L, -1))  /* is a C function? */
+    lua_pushvalue(L, LUA_GLOBALSINDEX);  /* return the thread's global env. */
+  else
+    lua_getfenv(L, -1);
+  return 1;
+}
+
+
+static int luaB_setfenv (lua_State *L) {
+  luaL_checktype(L, 2, LUA_TTABLE);
+  getfunc(L, 0);
+  lua_pushvalue(L, 2);
+  if (lua_isnumber(L, 1) && lua_tonumber(L, 1) == 0) {
+    /* change environment of current thread */
+    lua_pushthread(L);
+    lua_insert(L, -2);
+    lua_setfenv(L, -2);
+    return 0;
+  }
+  else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0)
+    luaL_error(L,
+          LUA_QL("setfenv") " cannot change environment of given object");
+  return 1;
+}
+
+
+static int luaB_rawequal (lua_State *L) {
+  luaL_checkany(L, 1);
+  luaL_checkany(L, 2);
+  lua_pushboolean(L, lua_rawequal(L, 1, 2));
+  return 1;
+}
+
+
+static int luaB_rawget (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checkany(L, 2);
+  lua_settop(L, 2);
+  lua_rawget(L, 1);
+  return 1;
+}
+
+static int luaB_rawset (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checkany(L, 2);
+  luaL_checkany(L, 3);
+  lua_settop(L, 3);
+  lua_rawset(L, 1);
+  return 1;
+}
+
+
+static int luaB_gcinfo (lua_State *L) {
+  lua_pushinteger(L, lua_getgccount(L));
+  return 1;
+}
+
+
+static int luaB_collectgarbage (lua_State *L) {
+  static const char *const opts[] = {"stop", "restart", "collect",
+    "count", "step", "setpause", "setstepmul", NULL};
+  static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
+    LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};
+  int o = luaL_checkoption(L, 1, "collect", opts);
+  int ex = luaL_optint(L, 2, 0);
+  int res = lua_gc(L, optsnum[o], ex);
+  switch (optsnum[o]) {
+    case LUA_GCCOUNT: {
+      int b = lua_gc(L, LUA_GCCOUNTB, 0);
+      lua_pushnumber(L, res + ((lua_Number)b/1024));
+      return 1;
+    }
+    case LUA_GCSTEP: {
+      lua_pushboolean(L, res);
+      return 1;
+    }
+    default: {
+      lua_pushnumber(L, res);
+      return 1;
+    }
+  }
+}
+
+
+static int luaB_type (lua_State *L) {
+  luaL_checkany(L, 1);
+  lua_pushstring(L, luaL_typename(L, 1));
+  return 1;
+}
+
+
+static int luaB_next (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  lua_settop(L, 2);  /* create a 2nd argument if there isn't one */
+  if (lua_next(L, 1))
+    return 2;
+  else {
+    lua_pushnil(L);
+    return 1;
+  }
+}
+
+
+static int luaB_pairs (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */
+  lua_pushvalue(L, 1);  /* state, */
+  lua_pushnil(L);  /* and initial value */
+  return 3;
+}
+
+
+static int ipairsaux (lua_State *L) {
+  int i = luaL_checkint(L, 2);
+  luaL_checktype(L, 1, LUA_TTABLE);
+  i++;  /* next value */
+  lua_pushinteger(L, i);
+  lua_rawgeti(L, 1, i);
+  return (lua_isnil(L, -1)) ? 0 : 2;
+}
+
+
+static int luaB_ipairs (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  lua_pushvalue(L, lua_upvalueindex(1));  /* return generator, */
+  lua_pushvalue(L, 1);  /* state, */
+  lua_pushinteger(L, 0);  /* and initial value */
+  return 3;
+}
+
+
+static int load_aux (lua_State *L, int status) {
+  if (status == 0)  /* OK? */
+    return 1;
+  else {
+    lua_pushnil(L);
+    lua_insert(L, -2);  /* put before error message */
+    return 2;  /* return nil plus error message */
+  }
+}
+
+
+static int luaB_loadstring (lua_State *L) {
+  size_t l;
+  const char *s = luaL_checklstring(L, 1, &l);
+  const char *chunkname = luaL_optstring(L, 2, s);
+  return load_aux(L, luaL_loadbuffer(L, s, l, chunkname));
+}
+
+
+static int luaB_loadfile (lua_State *L) {
+  const char *fname = luaL_optstring(L, 1, NULL);
+  return load_aux(L, luaL_loadfile(L, fname));
+}
+
+
+/*
+** Reader for generic `load' function: `lua_load' uses the
+** stack for internal stuff, so the reader cannot change the
+** stack top. Instead, it keeps its resulting string in a
+** reserved slot inside the stack.
+*/
+static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
+  (void)ud;  /* to avoid warnings */
+  luaL_checkstack(L, 2, "too many nested functions");
+  lua_pushvalue(L, 1);  /* get function */
+  lua_call(L, 0, 1);  /* call it */
+  if (lua_isnil(L, -1)) {
+    *size = 0;
+    return NULL;
+  }
+  else if (lua_isstring(L, -1)) {
+    lua_replace(L, 3);  /* save string in a reserved stack slot */
+    return lua_tolstring(L, 3, size);
+  }
+  else luaL_error(L, "reader function must return a string");
+  return NULL;  /* to avoid warnings */
+}
+
+
+static int luaB_load (lua_State *L) {
+  int status;
+  const char *cname = luaL_optstring(L, 2, "=(load)");
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  lua_settop(L, 3);  /* function, eventual name, plus one reserved slot */
+  status = lua_load(L, generic_reader, NULL, cname);
+  return load_aux(L, status);
+}
+
+
+static int luaB_dofile (lua_State *L) {
+  const char *fname = luaL_optstring(L, 1, NULL);
+  int n = lua_gettop(L);
+  if (luaL_loadfile(L, fname) != 0) lua_error(L);
+  lua_call(L, 0, LUA_MULTRET);
+  return lua_gettop(L) - n;
+}
+
+
+static int luaB_assert (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (!lua_toboolean(L, 1))
+    return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
+  return lua_gettop(L);
+}
+
+
+static int luaB_unpack (lua_State *L) {
+  int i, e, n;
+  luaL_checktype(L, 1, LUA_TTABLE);
+  i = luaL_optint(L, 2, 1);
+  e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
+  n = e - i + 1;  /* number of elements */
+  if (n <= 0) return 0;  /* empty range */
+  luaL_checkstack(L, n, "table too big to unpack");
+  for (; i<=e; i++)  /* push arg[i...e] */
+    lua_rawgeti(L, 1, i);
+  return n;
+}
+
+
+static int luaB_select (lua_State *L) {
+  int n = lua_gettop(L);
+  if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
+    lua_pushinteger(L, n-1);
+    return 1;
+  }
+  else {
+    int i = luaL_checkint(L, 1);
+    if (i < 0) i = n + i;
+    else if (i > n) i = n;
+    luaL_argcheck(L, 1 <= i, 1, "index out of range");
+    return n - i;
+  }
+}
+
+
+static int luaB_pcall (lua_State *L) {
+  int status;
+  luaL_checkany(L, 1);
+  status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
+  lua_pushboolean(L, (status == 0));
+  lua_insert(L, 1);
+  return lua_gettop(L);  /* return status + all results */
+}
+
+
+static int luaB_xpcall (lua_State *L) {
+  int status;
+  luaL_checkany(L, 2);
+  lua_settop(L, 2);
+  lua_insert(L, 1);  /* put error function under function to be called */
+  status = lua_pcall(L, 0, LUA_MULTRET, 1);
+  lua_pushboolean(L, (status == 0));
+  lua_replace(L, 1);
+  return lua_gettop(L);  /* return status + all results */
+}
+
+
+static int luaB_tostring (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (luaL_callmeta(L, 1, "__tostring"))  /* is there a metafield? */
+    return 1;  /* use its value */
+  switch (lua_type(L, 1)) {
+    case LUA_TNUMBER:
+      lua_pushstring(L, lua_tostring(L, 1));
+      break;
+    case LUA_TSTRING:
+      lua_pushvalue(L, 1);
+      break;
+    case LUA_TBOOLEAN:
+      lua_pushstring(L, (lua_toboolean(L, 1) ? "true" : "false"));
+      break;
+    case LUA_TNIL:
+      lua_pushliteral(L, "nil");
+      break;
+    default:
+      lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1));
+      break;
+  }
+  return 1;
+}
+
+
+static int luaB_newproxy (lua_State *L) {
+  lua_settop(L, 1);
+  lua_newuserdata(L, 0);  /* create proxy */
+  if (lua_toboolean(L, 1) == 0)
+    return 1;  /* no metatable */
+  else if (lua_isboolean(L, 1)) {
+    lua_newtable(L);  /* create a new metatable `m' ... */
+    lua_pushvalue(L, -1);  /* ... and mark `m' as a valid metatable */
+    lua_pushboolean(L, 1);
+    lua_rawset(L, lua_upvalueindex(1));  /* weaktable[m] = true */
+  }
+  else {
+    int validproxy = 0;  /* to check if weaktable[metatable(u)] == true */
+    if (lua_getmetatable(L, 1)) {
+      lua_rawget(L, lua_upvalueindex(1));
+      validproxy = lua_toboolean(L, -1);
+      lua_pop(L, 1);  /* remove value */
+    }
+    luaL_argcheck(L, validproxy, 1, "boolean or proxy expected");
+    lua_getmetatable(L, 1);  /* metatable is valid; get it */
+  }
+  lua_setmetatable(L, 2);
+  return 1;
+}
+
+
+static const luaL_Reg base_funcs[] = {
+  {"assert", luaB_assert},
+  {"collectgarbage", luaB_collectgarbage},
+  {"dofile", luaB_dofile},
+  {"error", luaB_error},
+  {"gcinfo", luaB_gcinfo},
+  {"getfenv", luaB_getfenv},
+  {"getmetatable", luaB_getmetatable},
+  {"loadfile", luaB_loadfile},
+  {"load", luaB_load},
+  {"loadstring", luaB_loadstring},
+  {"next", luaB_next},
+  {"pcall", luaB_pcall},
+  {"print", luaB_print},
+  {"rawequal", luaB_rawequal},
+  {"rawget", luaB_rawget},
+  {"rawset", luaB_rawset},
+  {"select", luaB_select},
+  {"setfenv", luaB_setfenv},
+  {"setmetatable", luaB_setmetatable},
+  {"tonumber", luaB_tonumber},
+  {"tostring", luaB_tostring},
+  {"type", luaB_type},
+  {"unpack", luaB_unpack},
+  {"xpcall", luaB_xpcall},
+  {NULL, NULL}
+};
+
+
+/*
+** {======================================================
+** Coroutine library
+** =======================================================
+*/
+
+#define CO_RUN	0	/* running */
+#define CO_SUS	1	/* suspended */
+#define CO_NOR	2	/* 'normal' (it resumed another coroutine) */
+#define CO_DEAD	3
+
+static const char *const statnames[] =
+    {"running", "suspended", "normal", "dead"};
+
+static int costatus (lua_State *L, lua_State *co) {
+  if (L == co) return CO_RUN;
+  switch (lua_status(co)) {
+    case LUA_YIELD:
+      return CO_SUS;
+    case 0: {
+      lua_Debug ar;
+      if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */
+        return CO_NOR;  /* it is running */
+      else if (lua_gettop(co) == 0)
+          return CO_DEAD;
+      else
+        return CO_SUS;  /* initial state */
+    }
+    default:  /* some error occured */
+      return CO_DEAD;
+  }
+}
+
+
+static int luaB_costatus (lua_State *L) {
+  lua_State *co = lua_tothread(L, 1);
+  luaL_argcheck(L, co, 1, "coroutine expected");
+  lua_pushstring(L, statnames[costatus(L, co)]);
+  return 1;
+}
+
+
+static int auxresume (lua_State *L, lua_State *co, int narg) {
+  int status = costatus(L, co);
+  if (!lua_checkstack(co, narg))
+    luaL_error(L, "too many arguments to resume");
+  if (status != CO_SUS) {
+    lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
+    return -1;  /* error flag */
+  }
+  lua_xmove(L, co, narg);
+  lua_setlevel(L, co);
+  status = lua_resume(co, narg);
+  if (status == 0 || status == LUA_YIELD) {
+    int nres = lua_gettop(co);
+    if (!lua_checkstack(L, nres))
+      luaL_error(L, "too many results to resume");
+    lua_xmove(co, L, nres);  /* move yielded values */
+    return nres;
+  }
+  else {
+    lua_xmove(co, L, 1);  /* move error message */
+    return -1;  /* error flag */
+  }
+}
+
+
+static int luaB_coresume (lua_State *L) {
+  lua_State *co = lua_tothread(L, 1);
+  int r;
+  luaL_argcheck(L, co, 1, "coroutine expected");
+  r = auxresume(L, co, lua_gettop(L) - 1);
+  if (r < 0) {
+    lua_pushboolean(L, 0);
+    lua_insert(L, -2);
+    return 2;  /* return false + error message */
+  }
+  else {
+    lua_pushboolean(L, 1);
+    lua_insert(L, -(r + 1));
+    return r + 1;  /* return true + `resume' returns */
+  }
+}
+
+
+static int luaB_auxwrap (lua_State *L) {
+  lua_State *co = lua_tothread(L, lua_upvalueindex(1));
+  int r = auxresume(L, co, lua_gettop(L));
+  if (r < 0) {
+    if (lua_isstring(L, -1)) {  /* error object is a string? */
+      luaL_where(L, 1);  /* add extra info */
+      lua_insert(L, -2);
+      lua_concat(L, 2);
+    }
+    lua_error(L);  /* propagate error */
+  }
+  return r;
+}
+
+
+static int luaB_cocreate (lua_State *L) {
+  lua_State *NL = lua_newthread(L);
+  luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
+    "Lua function expected");
+  lua_pushvalue(L, 1);  /* move function to top */
+  lua_xmove(L, NL, 1);  /* move function from L to NL */
+  return 1;
+}
+
+
+static int luaB_cowrap (lua_State *L) {
+  luaB_cocreate(L);
+  lua_pushcclosure(L, luaB_auxwrap, 1);
+  return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+  return lua_yield(L, lua_gettop(L));
+}
+
+
+static int luaB_corunning (lua_State *L) {
+  if (lua_pushthread(L))
+    lua_pushnil(L);  /* main thread is not a coroutine */
+  return 1;
+}
+
+
+static const luaL_Reg co_funcs[] = {
+  {"create", luaB_cocreate},
+  {"resume", luaB_coresume},
+  {"running", luaB_corunning},
+  {"status", luaB_costatus},
+  {"wrap", luaB_cowrap},
+  {"yield", luaB_yield},
+  {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+static void auxopen (lua_State *L, const char *name,
+                     lua_CFunction f, lua_CFunction u) {
+  lua_pushcfunction(L, u);
+  lua_pushcclosure(L, f, 1);
+  lua_setfield(L, -2, name);
+}
+
+
+static void base_open (lua_State *L) {
+  /* set global _G */
+  lua_pushvalue(L, LUA_GLOBALSINDEX);
+  lua_setglobal(L, "_G");
+  /* open lib into global table */
+  luaL_register(L, "_G", base_funcs);
+  lua_pushliteral(L, LUA_VERSION);
+  lua_setglobal(L, "_VERSION");  /* set global _VERSION */
+  /* `ipairs' and `pairs' need auxliliary functions as upvalues */
+  auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
+  auxopen(L, "pairs", luaB_pairs, luaB_next);
+  /* `newproxy' needs a weaktable as upvalue */
+  lua_createtable(L, 0, 1);  /* new table `w' */
+  lua_pushvalue(L, -1);  /* `w' will be its own metatable */
+  lua_setmetatable(L, -2);
+  lua_pushliteral(L, "kv");
+  lua_setfield(L, -2, "__mode");  /* metatable(w).__mode = "kv" */
+  lua_pushcclosure(L, luaB_newproxy, 1);
+  lua_setglobal(L, "newproxy");  /* set global `newproxy' */
+}
+
+
+LUALIB_API int luaopen_base (lua_State *L) {
+  base_open(L);
+  luaL_register(L, LUA_COLIBNAME, co_funcs);
+  return 2;
+}
+

=== added file 'lua/lcode.c'
--- lua/lcode.c	1970-01-01 00:00:00 +0000
+++ lua/lcode.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,841 @@
+/*
+** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stdlib.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lcode_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "ltable.h"
+
+
+#define hasjumps(e)	((e)->t != (e)->f)
+
+
+static int isnumeral(expdesc *e) {
+  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
+}
+
+
+void luaK_nil (FuncState *fs, int from, int n) {
+  Instruction *previous;
+  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
+    if (fs->pc == 0) {  /* function start? */
+      if (from >= fs->nactvar)
+        return;  /* positions are already clean */
+    }
+    else {
+      previous = &fs->f->code[fs->pc-1];
+      if (GET_OPCODE(*previous) == OP_LOADNIL) {
+        int pfrom = GETARG_A(*previous);
+        int pto = GETARG_B(*previous);
+        if (pfrom <= from && from <= pto+1) {  /* can connect both? */
+          if (from+n-1 > pto)
+            SETARG_B(*previous, from+n-1);
+          return;
+        }
+      }
+    }
+  }
+  luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */
+}
+
+
+int luaK_jump (FuncState *fs) {
+  int jpc = fs->jpc;  /* save list of jumps to here */
+  int j;
+  fs->jpc = NO_JUMP;
+  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+  luaK_concat(fs, &j, jpc);  /* keep them on hold */
+  return j;
+}
+
+
+void luaK_ret (FuncState *fs, int first, int nret) {
+  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+}
+
+
+static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
+  luaK_codeABC(fs, op, A, B, C);
+  return luaK_jump(fs);
+}
+
+
+static void fixjump (FuncState *fs, int pc, int dest) {
+  Instruction *jmp = &fs->f->code[pc];
+  int offset = dest-(pc+1);
+  lua_assert(dest != NO_JUMP);
+  if (abs(offset) > MAXARG_sBx)
+    luaX_syntaxerror(fs->ls, "control structure too long");
+  SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** returns current `pc' and marks it as a jump target (to avoid wrong
+** optimizations with consecutive instructions not in the same basic block).
+*/
+int luaK_getlabel (FuncState *fs) {
+  fs->lasttarget = fs->pc;
+  return fs->pc;
+}
+
+
+static int getjump (FuncState *fs, int pc) {
+  int offset = GETARG_sBx(fs->f->code[pc]);
+  if (offset == NO_JUMP)  /* point to itself represents end of list */
+    return NO_JUMP;  /* end of list */
+  else
+    return (pc+1)+offset;  /* turn offset into absolute position */
+}
+
+
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+  Instruction *pi = &fs->f->code[pc];
+  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
+    return pi-1;
+  else
+    return pi;
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** (or produce an inverted value)
+*/
+static int need_value (FuncState *fs, int list) {
+  for (; list != NO_JUMP; list = getjump(fs, list)) {
+    Instruction i = *getjumpcontrol(fs, list);
+    if (GET_OPCODE(i) != OP_TESTSET) return 1;
+  }
+  return 0;  /* not found */
+}
+
+
+static int patchtestreg (FuncState *fs, int node, int reg) {
+  Instruction *i = getjumpcontrol(fs, node);
+  if (GET_OPCODE(*i) != OP_TESTSET)
+    return 0;  /* cannot patch other instructions */
+  if (reg != NO_REG && reg != GETARG_B(*i))
+    SETARG_A(*i, reg);
+  else  /* no register to put value or register already has the value */
+    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
+
+  return 1;
+}
+
+
+static void removevalues (FuncState *fs, int list) {
+  for (; list != NO_JUMP; list = getjump(fs, list))
+      patchtestreg(fs, list, NO_REG);
+}
+
+
+static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
+                          int dtarget) {
+  while (list != NO_JUMP) {
+    int next = getjump(fs, list);
+    if (patchtestreg(fs, list, reg))
+      fixjump(fs, list, vtarget);
+    else
+      fixjump(fs, list, dtarget);  /* jump to default target */
+    list = next;
+  }
+}
+
+
+static void dischargejpc (FuncState *fs) {
+  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
+  fs->jpc = NO_JUMP;
+}
+
+
+void luaK_patchlist (FuncState *fs, int list, int target) {
+  if (target == fs->pc)
+    luaK_patchtohere(fs, list);
+  else {
+    lua_assert(target < fs->pc);
+    patchlistaux(fs, list, target, NO_REG, target);
+  }
+}
+
+
+void luaK_patchtohere (FuncState *fs, int list) {
+  luaK_getlabel(fs);
+  luaK_concat(fs, &fs->jpc, list);
+}
+
+
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+  if (l2 == NO_JUMP) return;
+  else if (*l1 == NO_JUMP)
+    *l1 = l2;
+  else {
+    int list = *l1;
+    int next;
+    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
+      list = next;
+    fixjump(fs, list, l2);
+  }
+}
+
+
+void luaK_checkstack (FuncState *fs, int n) {
+  int newstack = fs->freereg + n;
+  if (newstack > fs->f->maxstacksize) {
+    if (newstack >= MAXSTACK)
+      luaX_syntaxerror(fs->ls, "function or expression too complex");
+    fs->f->maxstacksize = cast_byte(newstack);
+  }
+}
+
+
+void luaK_reserveregs (FuncState *fs, int n) {
+  luaK_checkstack(fs, n);
+  fs->freereg += n;
+}
+
+
+static void freereg (FuncState *fs, int reg) {
+  if (!ISK(reg) && reg >= fs->nactvar) {
+    fs->freereg--;
+    lua_assert(reg == fs->freereg);
+  }
+}
+
+
+static void freeexp (FuncState *fs, expdesc *e) {
+  if (e->k == VNONRELOC)
+    freereg(fs, e->u.s.info);
+}
+
+
+static int addk (FuncState *fs, TValue *k, TValue *v) {
+  lua_State *L = fs->L;
+  TValue *idx = luaH_set(L, fs->h, k);
+  Proto *f = fs->f;
+  int oldsize = f->sizek;
+  if (ttisnumber(idx)) {
+    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
+    return cast_int(nvalue(idx));
+  }
+  else {  /* constant not found; create a new entry */
+    setnvalue(idx, cast_num(fs->nk));
+    luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
+                    MAXARG_Bx, "constant table overflow");
+    while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
+    setobj(L, &f->k[fs->nk], v);
+    luaC_barrier(L, f, v);
+    return fs->nk++;
+  }
+}
+
+
+int luaK_stringK (FuncState *fs, TString *s) {
+  TValue o;
+  setsvalue(fs->L, &o, s);
+  return addk(fs, &o, &o);
+}
+
+
+int luaK_numberK (FuncState *fs, lua_Number r) {
+  TValue o;
+  setnvalue(&o, r);
+  return addk(fs, &o, &o);
+}
+
+
+static int boolK (FuncState *fs, int b) {
+  TValue o;
+  setbvalue(&o, b);
+  return addk(fs, &o, &o);
+}
+
+
+static int nilK (FuncState *fs) {
+  TValue k, v;
+  setnilvalue(&v);
+  /* cannot use nil as key; instead use table itself to represent nil */
+  sethvalue(fs->L, &k, fs->h);
+  return addk(fs, &k, &v);
+}
+
+
+void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    SETARG_C(getcode(fs, e), nresults+1);
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), nresults+1);
+    SETARG_A(getcode(fs, e), fs->freereg);
+    luaK_reserveregs(fs, 1);
+  }
+}
+
+
+void luaK_setoneret (FuncState *fs, expdesc *e) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    e->k = VNONRELOC;
+    e->u.s.info = GETARG_A(getcode(fs, e));
+  }
+  else if (e->k == VVARARG) {
+    SETARG_B(getcode(fs, e), 2);
+    e->k = VRELOCABLE;  /* can relocate its simple result */
+  }
+}
+
+
+void luaK_dischargevars (FuncState *fs, expdesc *e) {
+  switch (e->k) {
+    case VLOCAL: {
+      e->k = VNONRELOC;
+      break;
+    }
+    case VUPVAL: {
+      e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VGLOBAL: {
+      e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VINDEXED: {
+      freereg(fs, e->u.s.aux);
+      freereg(fs, e->u.s.info);
+      e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VVARARG:
+    case VCALL: {
+      luaK_setoneret(fs, e);
+      break;
+    }
+    default: break;  /* there is one value available (somewhere) */
+  }
+}
+
+
+static int code_label (FuncState *fs, int A, int b, int jump) {
+  luaK_getlabel(fs);  /* those instructions may be jump targets */
+  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: {
+      luaK_nil(fs, reg, 1);
+      break;
+    }
+    case VFALSE:  case VTRUE: {
+      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
+      break;
+    }
+    case VK: {
+      luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
+      break;
+    }
+    case VKNUM: {
+      luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
+      break;
+    }
+    case VRELOCABLE: {
+      Instruction *pc = &getcode(fs, e);
+      SETARG_A(*pc, reg);
+      break;
+    }
+    case VNONRELOC: {
+      if (reg != e->u.s.info)
+        luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
+      break;
+    }
+    default: {
+      lua_assert(e->k == VVOID || e->k == VJMP);
+      return;  /* nothing to do... */
+    }
+  }
+  e->u.s.info = reg;
+  e->k = VNONRELOC;
+}
+
+
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+  if (e->k != VNONRELOC) {
+    luaK_reserveregs(fs, 1);
+    discharge2reg(fs, e, fs->freereg-1);
+  }
+}
+
+
+static void exp2reg (FuncState *fs, expdesc *e, int reg) {
+  discharge2reg(fs, e, reg);
+  if (e->k == VJMP)
+    luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */
+  if (hasjumps(e)) {
+    int final;  /* position after whole expression */
+    int p_f = NO_JUMP;  /* position of an eventual LOAD false */
+    int p_t = NO_JUMP;  /* position of an eventual LOAD true */
+    if (need_value(fs, e->t) || need_value(fs, e->f)) {
+      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
+      p_f = code_label(fs, reg, 0, 1);
+      p_t = code_label(fs, reg, 1, 0);
+      luaK_patchtohere(fs, fj);
+    }
+    final = luaK_getlabel(fs);
+    patchlistaux(fs, e->f, final, reg, p_f);
+    patchlistaux(fs, e->t, final, reg, p_t);
+  }
+  e->f = e->t = NO_JUMP;
+  e->u.s.info = reg;
+  e->k = VNONRELOC;
+}
+
+
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  freeexp(fs, e);
+  luaK_reserveregs(fs, 1);
+  exp2reg(fs, e, fs->freereg - 1);
+}
+
+
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  if (e->k == VNONRELOC) {
+    if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */
+    if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */
+      exp2reg(fs, e, e->u.s.info);  /* put value on it */
+      return e->u.s.info;
+    }
+  }
+  luaK_exp2nextreg(fs, e);  /* default */
+  return e->u.s.info;
+}
+
+
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+  if (hasjumps(e))
+    luaK_exp2anyreg(fs, e);
+  else
+    luaK_dischargevars(fs, e);
+}
+
+
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+  luaK_exp2val(fs, e);
+  switch (e->k) {
+    case VKNUM:
+    case VTRUE:
+    case VFALSE:
+    case VNIL: {
+      if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
+        e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
+                      (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
+                                        boolK(fs, (e->k == VTRUE));
+        e->k = VK;
+        return RKASK(e->u.s.info);
+      }
+      else break;
+    }
+    case VK: {
+      if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */
+        return RKASK(e->u.s.info);
+      else break;
+    }
+    default: break;
+  }
+  /* not a constant in the right range: put it in a register */
+  return luaK_exp2anyreg(fs, e);
+}
+
+
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
+  switch (var->k) {
+    case VLOCAL: {
+      freeexp(fs, ex);
+      exp2reg(fs, ex, var->u.s.info);
+      return;
+    }
+    case VUPVAL: {
+      int e = luaK_exp2anyreg(fs, ex);
+      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
+      break;
+    }
+    case VGLOBAL: {
+      int e = luaK_exp2anyreg(fs, ex);
+      luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
+      break;
+    }
+    case VINDEXED: {
+      int e = luaK_exp2RK(fs, ex);
+      luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
+      break;
+    }
+    default: {
+      lua_assert(0);  /* invalid var kind to store */
+      break;
+    }
+  }
+  freeexp(fs, ex);
+}
+
+
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+  int func;
+  luaK_exp2anyreg(fs, e);
+  freeexp(fs, e);
+  func = fs->freereg;
+  luaK_reserveregs(fs, 2);
+  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
+  freeexp(fs, key);
+  e->u.s.info = func;
+  e->k = VNONRELOC;
+}
+
+
+static void invertjump (FuncState *fs, expdesc *e) {
+  Instruction *pc = getjumpcontrol(fs, e->u.s.info);
+  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
+                                           GET_OPCODE(*pc) != OP_TEST);
+  SETARG_A(*pc, !(GETARG_A(*pc)));
+}
+
+
+static int jumponcond (FuncState *fs, expdesc *e, int cond) {
+  if (e->k == VRELOCABLE) {
+    Instruction ie = getcode(fs, e);
+    if (GET_OPCODE(ie) == OP_NOT) {
+      fs->pc--;  /* remove previous OP_NOT */
+      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
+    }
+    /* else go through */
+  }
+  discharge2anyreg(fs, e);
+  freeexp(fs, e);
+  return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
+}
+
+
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VK: case VKNUM: case VTRUE: {
+      pc = NO_JUMP;  /* always true; do nothing */
+      break;
+    }
+    case VFALSE: {
+      pc = luaK_jump(fs);  /* always jump */
+      break;
+    }
+    case VJMP: {
+      invertjump(fs, e);
+      pc = e->u.s.info;
+      break;
+    }
+    default: {
+      pc = jumponcond(fs, e, 0);
+      break;
+    }
+  }
+  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
+  luaK_patchtohere(fs, e->t);
+  e->t = NO_JUMP;
+}
+
+
+static void luaK_goiffalse (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: case VFALSE: {
+      pc = NO_JUMP;  /* always false; do nothing */
+      break;
+    }
+    case VTRUE: {
+      pc = luaK_jump(fs);  /* always jump */
+      break;
+    }
+    case VJMP: {
+      pc = e->u.s.info;
+      break;
+    }
+    default: {
+      pc = jumponcond(fs, e, 1);
+      break;
+    }
+  }
+  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
+  luaK_patchtohere(fs, e->f);
+  e->f = NO_JUMP;
+}
+
+
+static void codenot (FuncState *fs, expdesc *e) {
+  luaK_dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: case VFALSE: {
+      e->k = VTRUE;
+      break;
+    }
+    case VK: case VKNUM: case VTRUE: {
+      e->k = VFALSE;
+      break;
+    }
+    case VJMP: {
+      invertjump(fs, e);
+      break;
+    }
+    case VRELOCABLE:
+    case VNONRELOC: {
+      discharge2anyreg(fs, e);
+      freeexp(fs, e);
+      e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
+      e->k = VRELOCABLE;
+      break;
+    }
+    default: {
+      lua_assert(0);  /* cannot happen */
+      break;
+    }
+  }
+  /* interchange true and false lists */
+  { int temp = e->f; e->f = e->t; e->t = temp; }
+  removevalues(fs, e->f);
+  removevalues(fs, e->t);
+}
+
+
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+  t->u.s.aux = luaK_exp2RK(fs, k);
+  t->k = VINDEXED;
+}
+
+
+static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
+  lua_Number v1, v2, r;
+  if (!isnumeral(e1) || !isnumeral(e2)) return 0;
+  v1 = e1->u.nval;
+  v2 = e2->u.nval;
+  switch (op) {
+    case OP_ADD: r = luai_numadd(v1, v2); break;
+    case OP_SUB: r = luai_numsub(v1, v2); break;
+    case OP_MUL: r = luai_nummul(v1, v2); break;
+    case OP_DIV:
+      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
+      r = luai_numdiv(v1, v2); break;
+    case OP_MOD:
+      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
+      r = luai_nummod(v1, v2); break;
+    case OP_POW: r = luai_numpow(v1, v2); break;
+    case OP_UNM: r = luai_numunm(v1); break;
+    case OP_LEN: return 0;  /* no constant folding for 'len' */
+    default: lua_assert(0); r = 0; break;
+  }
+  if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
+  e1->u.nval = r;
+  return 1;
+}
+
+
+static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+  if (constfolding(op, e1, e2))
+    return;
+  else {
+    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
+    int o1 = luaK_exp2RK(fs, e1);
+    if (o1 > o2) {
+      freeexp(fs, e1);
+      freeexp(fs, e2);
+    }
+    else {
+      freeexp(fs, e2);
+      freeexp(fs, e1);
+    }
+    e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
+    e1->k = VRELOCABLE;
+  }
+}
+
+
+static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
+                                                          expdesc *e2) {
+  int o1 = luaK_exp2RK(fs, e1);
+  int o2 = luaK_exp2RK(fs, e2);
+  freeexp(fs, e2);
+  freeexp(fs, e1);
+  if (cond == 0 && op != OP_EQ) {
+    int temp;  /* exchange args to replace by `<' or `<=' */
+    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
+    cond = 1;
+  }
+  e1->u.s.info = condjump(fs, op, cond, o1, o2);
+  e1->k = VJMP;
+}
+
+
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+  expdesc e2;
+  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
+  switch (op) {
+    case OPR_MINUS: {
+      if (!isnumeral(e))
+        luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
+      codearith(fs, OP_UNM, e, &e2);
+      break;
+    }
+    case OPR_NOT: codenot(fs, e); break;
+    case OPR_LEN: {
+      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
+      codearith(fs, OP_LEN, e, &e2);
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+  switch (op) {
+    case OPR_AND: {
+      luaK_goiftrue(fs, v);
+      break;
+    }
+    case OPR_OR: {
+      luaK_goiffalse(fs, v);
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
+      break;
+    }
+    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+    case OPR_MOD: case OPR_POW: {
+      if (!isnumeral(v)) luaK_exp2RK(fs, v);
+      break;
+    }
+    default: {
+      luaK_exp2RK(fs, v);
+      break;
+    }
+  }
+}
+
+
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
+  switch (op) {
+    case OPR_AND: {
+      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
+      luaK_dischargevars(fs, e2);
+      luaK_concat(fs, &e2->f, e1->f);
+      *e1 = *e2;
+      break;
+    }
+    case OPR_OR: {
+      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
+      luaK_dischargevars(fs, e2);
+      luaK_concat(fs, &e2->t, e1->t);
+      *e1 = *e2;
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2val(fs, e2);
+      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
+        lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
+        freeexp(fs, e1);
+        SETARG_B(getcode(fs, e2), e1->u.s.info);
+        e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
+      }
+      else {
+        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
+        codearith(fs, OP_CONCAT, e1, e2);
+      }
+      break;
+    }
+    case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
+    case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
+    case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
+    case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
+    case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
+    case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
+    case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
+    case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
+    case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
+    case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
+    case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
+    case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
+    default: lua_assert(0);
+  }
+}
+
+
+void luaK_fixline (FuncState *fs, int line) {
+  fs->f->lineinfo[fs->pc - 1] = line;
+}
+
+
+static int luaK_code (FuncState *fs, Instruction i, int line) {
+  Proto *f = fs->f;
+  dischargejpc(fs);  /* `pc' will change */
+  /* put new instruction in code array */
+  luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
+                  MAX_INT, "code size overflow");
+  f->code[fs->pc] = i;
+  /* save corresponding line information */
+  luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
+                  MAX_INT, "code size overflow");
+  f->lineinfo[fs->pc] = line;
+  return fs->pc++;
+}
+
+
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+  lua_assert(getOpMode(o) == iABC);
+  lua_assert(getBMode(o) != OpArgN || b == 0);
+  lua_assert(getCMode(o) != OpArgN || c == 0);
+  return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
+}
+
+
+int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
+  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
+  lua_assert(getCMode(o) == OpArgN);
+  return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
+}
+
+
+void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
+  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
+  int b = (tostore == LUA_MULTRET) ? 0 : tostore;
+  lua_assert(tostore != 0);
+  if (c <= MAXARG_C)
+    luaK_codeABC(fs, OP_SETLIST, base, b, c);
+  else {
+    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
+    luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
+  }
+  fs->freereg = base + 1;  /* free registers with list values */
+}
+

=== added file 'lua/lcode.h'
--- lua/lcode.h	1970-01-01 00:00:00 +0000
+++ lua/lcode.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,76 @@
+/*
+** $Id: lcode.h,v 1.48.1.1 2007/12/27 13:02:25 roberto Exp $
+** Code generator for Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lcode_h
+#define lcode_h
+
+#include "llex.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums
+*/
+typedef enum BinOpr {
+  OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
+  OPR_CONCAT,
+  OPR_NE, OPR_EQ,
+  OPR_LT, OPR_LE, OPR_GT, OPR_GE,
+  OPR_AND, OPR_OR,
+  OPR_NOBINOPR
+} BinOpr;
+
+
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
+
+
+#define getcode(fs,e)	((fs)->f->code[(e)->u.s.info])
+
+#define luaK_codeAsBx(fs,o,A,sBx)	luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
+
+#define luaK_setmultret(fs,e)	luaK_setreturns(fs, e, LUA_MULTRET)
+
+LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
+LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
+LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
+LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
+LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
+LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
+LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
+LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
+LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
+LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
+LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
+LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
+LUAI_FUNC int luaK_jump (FuncState *fs);
+LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
+LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
+LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
+LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
+LUAI_FUNC int luaK_getlabel (FuncState *fs);
+LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
+LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
+LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
+
+
+#endif

=== added file 'lua/ldblib.c'
--- lua/ldblib.c	1970-01-01 00:00:00 +0000
+++ lua/ldblib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,399 @@
+/*
+** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $
+** Interface from Lua to its debug API
+** See Copyright Notice in lua.h
+*/
+
+
+#ifdef USE_GRUB_LIB
+#include <grub/normal.h>   /* for grub_cmdline_get() */
+#else /* ! USE_GRUB_LIB */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define ldblib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+static int db_getregistry (lua_State *L) {
+  lua_pushvalue(L, LUA_REGISTRYINDEX);
+  return 1;
+}
+
+
+static int db_getmetatable (lua_State *L) {
+  luaL_checkany(L, 1);
+  if (!lua_getmetatable(L, 1)) {
+    lua_pushnil(L);  /* no metatable */
+  }
+  return 1;
+}
+
+
+static int db_setmetatable (lua_State *L) {
+  int t = lua_type(L, 2);
+  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
+                    "nil or table expected");
+  lua_settop(L, 2);
+  lua_pushboolean(L, lua_setmetatable(L, 1));
+  return 1;
+}
+
+
+static int db_getfenv (lua_State *L) {
+  lua_getfenv(L, 1);
+  return 1;
+}
+
+
+static int db_setfenv (lua_State *L) {
+  luaL_checktype(L, 2, LUA_TTABLE);
+  lua_settop(L, 2);
+  if (lua_setfenv(L, 1) == 0)
+    luaL_error(L, LUA_QL("setfenv")
+                  " cannot change environment of given object");
+  return 1;
+}
+
+
+static void settabss (lua_State *L, const char *i, const char *v) {
+  lua_pushstring(L, v);
+  lua_setfield(L, -2, i);
+}
+
+
+static void settabsi (lua_State *L, const char *i, int v) {
+  lua_pushinteger(L, v);
+  lua_setfield(L, -2, i);
+}
+
+
+static lua_State *getthread (lua_State *L, int *arg) {
+  if (lua_isthread(L, 1)) {
+    *arg = 1;
+    return lua_tothread(L, 1);
+  }
+  else {
+    *arg = 0;
+    return L;
+  }
+}
+
+
+static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
+  if (L == L1) {
+    lua_pushvalue(L, -2);
+    lua_remove(L, -3);
+  }
+  else
+    lua_xmove(L1, L, 1);
+  lua_setfield(L, -2, fname);
+}
+
+
+static int db_getinfo (lua_State *L) {
+  lua_Debug ar;
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  const char *options = luaL_optstring(L, arg+2, "flnSu");
+  if (lua_isnumber(L, arg+1)) {
+    if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
+      lua_pushnil(L);  /* level out of range */
+      return 1;
+    }
+  }
+  else if (lua_isfunction(L, arg+1)) {
+    lua_pushfstring(L, ">%s", options);
+    options = lua_tostring(L, -1);
+    lua_pushvalue(L, arg+1);
+    lua_xmove(L, L1, 1);
+  }
+  else
+    return luaL_argerror(L, arg+1, "function or level expected");
+  if (!lua_getinfo(L1, options, &ar))
+    return luaL_argerror(L, arg+2, "invalid option");
+  lua_createtable(L, 0, 2);
+  if (strchr(options, 'S')) {
+    settabss(L, "source", ar.source);
+    settabss(L, "short_src", ar.short_src);
+    settabsi(L, "linedefined", ar.linedefined);
+    settabsi(L, "lastlinedefined", ar.lastlinedefined);
+    settabss(L, "what", ar.what);
+  }
+  if (strchr(options, 'l'))
+    settabsi(L, "currentline", ar.currentline);
+  if (strchr(options, 'u'))
+    settabsi(L, "nups", ar.nups);
+  if (strchr(options, 'n')) {
+    settabss(L, "name", ar.name);
+    settabss(L, "namewhat", ar.namewhat);
+  }
+  if (strchr(options, 'L'))
+    treatstackoption(L, L1, "activelines");
+  if (strchr(options, 'f'))
+    treatstackoption(L, L1, "func");
+  return 1;  /* return table */
+}
+    
+
+static int db_getlocal (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  lua_Debug ar;
+  const char *name;
+  if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
+    return luaL_argerror(L, arg+1, "level out of range");
+  name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
+  if (name) {
+    lua_xmove(L1, L, 1);
+    lua_pushstring(L, name);
+    lua_pushvalue(L, -2);
+    return 2;
+  }
+  else {
+    lua_pushnil(L);
+    return 1;
+  }
+}
+
+
+static int db_setlocal (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  lua_Debug ar;
+  if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
+    return luaL_argerror(L, arg+1, "level out of range");
+  luaL_checkany(L, arg+3);
+  lua_settop(L, arg+3);
+  lua_xmove(L, L1, 1);
+  lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
+  return 1;
+}
+
+
+static int auxupvalue (lua_State *L, int get) {
+  const char *name;
+  int n = luaL_checkint(L, 2);
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  if (lua_iscfunction(L, 1)) return 0;  /* cannot touch C upvalues from Lua */
+  name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
+  if (name == NULL) return 0;
+  lua_pushstring(L, name);
+  lua_insert(L, -(get+1));
+  return get + 1;
+}
+
+
+static int db_getupvalue (lua_State *L) {
+  return auxupvalue(L, 1);
+}
+
+
+static int db_setupvalue (lua_State *L) {
+  luaL_checkany(L, 3);
+  return auxupvalue(L, 0);
+}
+
+
+
+static const char KEY_HOOK = 'h';
+
+
+static void hookf (lua_State *L, lua_Debug *ar) {
+  static const char *const hooknames[] =
+    {"call", "return", "line", "count", "tail return"};
+  lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+  lua_rawget(L, LUA_REGISTRYINDEX);
+  lua_pushlightuserdata(L, L);
+  lua_rawget(L, -2);
+  if (lua_isfunction(L, -1)) {
+    lua_pushstring(L, hooknames[(int)ar->event]);
+    if (ar->currentline >= 0)
+      lua_pushinteger(L, ar->currentline);
+    else lua_pushnil(L);
+    lua_assert(lua_getinfo(L, "lS", ar));
+    lua_call(L, 2, 0);
+  }
+}
+
+
+static int makemask (const char *smask, int count) {
+  int mask = 0;
+  if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
+  if (strchr(smask, 'r')) mask |= LUA_MASKRET;
+  if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+  if (count > 0) mask |= LUA_MASKCOUNT;
+  return mask;
+}
+
+
+static char *unmakemask (int mask, char *smask) {
+  int i = 0;
+  if (mask & LUA_MASKCALL) smask[i++] = 'c';
+  if (mask & LUA_MASKRET) smask[i++] = 'r';
+  if (mask & LUA_MASKLINE) smask[i++] = 'l';
+  smask[i] = '\0';
+  return smask;
+}
+
+
+static void gethooktable (lua_State *L) {
+  lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+  lua_rawget(L, LUA_REGISTRYINDEX);
+  if (!lua_istable(L, -1)) {
+    lua_pop(L, 1);
+    lua_createtable(L, 0, 1);
+    lua_pushlightuserdata(L, (void *)&KEY_HOOK);
+    lua_pushvalue(L, -2);
+    lua_rawset(L, LUA_REGISTRYINDEX);
+  }
+}
+
+
+static int db_sethook (lua_State *L) {
+  int arg, mask, count;
+  lua_Hook func;
+  lua_State *L1 = getthread(L, &arg);
+  if (lua_isnoneornil(L, arg+1)) {
+    lua_settop(L, arg+1);
+    func = NULL; mask = 0; count = 0;  /* turn off hooks */
+  }
+  else {
+    const char *smask = luaL_checkstring(L, arg+2);
+    luaL_checktype(L, arg+1, LUA_TFUNCTION);
+    count = luaL_optint(L, arg+3, 0);
+    func = hookf; mask = makemask(smask, count);
+  }
+  gethooktable(L);
+  lua_pushlightuserdata(L, L1);
+  lua_pushvalue(L, arg+1);
+  lua_rawset(L, -3);  /* set new hook */
+  lua_pop(L, 1);  /* remove hook table */
+  lua_sethook(L1, func, mask, count);  /* set hooks */
+  return 0;
+}
+
+
+static int db_gethook (lua_State *L) {
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  char buff[5];
+  int mask = lua_gethookmask(L1);
+  lua_Hook hook = lua_gethook(L1);
+  if (hook != NULL && hook != hookf)  /* external hook? */
+    lua_pushliteral(L, "external hook");
+  else {
+    gethooktable(L);
+    lua_pushlightuserdata(L, L1);
+    lua_rawget(L, -2);   /* get hook */
+    lua_remove(L, -2);  /* remove hook table */
+  }
+  lua_pushstring(L, unmakemask(mask, buff));
+  lua_pushinteger(L, lua_gethookcount(L1));
+  return 3;
+}
+
+
+static int db_debug (lua_State *L) {
+  for (;;) {
+    char buffer[250];
+    if (grub_cmdline_get("lua_debug> ", buffer, sizeof(buffer), 0, 1) == 0 ||
+        strcmp(buffer, "cont\n") == 0)
+      return 0;
+    if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
+        lua_pcall(L, 0, 0, 0)) {
+      grub_printf("%s\n", lua_tostring(L, -1));
+    }
+    lua_settop(L, 0);  /* remove eventual returns */
+  }
+}
+
+
+#define LEVELS1	12	/* size of the first part of the stack */
+#define LEVELS2	10	/* size of the second part of the stack */
+
+static int db_errorfb (lua_State *L) {
+  int level;
+  int firstpart = 1;  /* still before eventual `...' */
+  int arg;
+  lua_State *L1 = getthread(L, &arg);
+  lua_Debug ar;
+  if (lua_isnumber(L, arg+2)) {
+    level = (int)lua_tointeger(L, arg+2);
+    lua_pop(L, 1);
+  }
+  else
+    level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */
+  if (lua_gettop(L) == arg)
+    lua_pushliteral(L, "");
+  else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */
+  else lua_pushliteral(L, "\n");
+  lua_pushliteral(L, "stack traceback:");
+  while (lua_getstack(L1, level++, &ar)) {
+    if (level > LEVELS1 && firstpart) {
+      /* no more than `LEVELS2' more levels? */
+      if (!lua_getstack(L1, level+LEVELS2, &ar))
+        level--;  /* keep going */
+      else {
+        lua_pushliteral(L, "\n\t...");  /* too many levels */
+        while (lua_getstack(L1, level+LEVELS2, &ar))  /* find last levels */
+          level++;
+      }
+      firstpart = 0;
+      continue;
+    }
+    lua_pushliteral(L, "\n\t");
+    lua_getinfo(L1, "Snl", &ar);
+    lua_pushfstring(L, "%s:", ar.short_src);
+    if (ar.currentline > 0)
+      lua_pushfstring(L, "%d:", ar.currentline);
+    if (*ar.namewhat != '\0')  /* is there a name? */
+        lua_pushfstring(L, " in function " LUA_QS, ar.name);
+    else {
+      if (*ar.what == 'm')  /* main? */
+        lua_pushfstring(L, " in main chunk");
+      else if (*ar.what == 'C' || *ar.what == 't')
+        lua_pushliteral(L, " ?");  /* C function or tail call */
+      else
+        lua_pushfstring(L, " in function <%s:%d>",
+                           ar.short_src, ar.linedefined);
+    }
+    lua_concat(L, lua_gettop(L) - arg);
+  }
+  lua_concat(L, lua_gettop(L) - arg);
+  return 1;
+}
+
+
+static const luaL_Reg dblib[] = {
+  {"debug", db_debug},
+  {"getfenv", db_getfenv},
+  {"gethook", db_gethook},
+  {"getinfo", db_getinfo},
+  {"getlocal", db_getlocal},
+  {"getregistry", db_getregistry},
+  {"getmetatable", db_getmetatable},
+  {"getupvalue", db_getupvalue},
+  {"setfenv", db_setfenv},
+  {"sethook", db_sethook},
+  {"setlocal", db_setlocal},
+  {"setmetatable", db_setmetatable},
+  {"setupvalue", db_setupvalue},
+  {"traceback", db_errorfb},
+  {NULL, NULL}
+};
+
+
+LUALIB_API int luaopen_debug (lua_State *L) {
+  luaL_register(L, LUA_DBLIBNAME, dblib);
+  return 1;
+}
+

=== added file 'lua/ldebug.c'
--- lua/ldebug.c	1970-01-01 00:00:00 +0000
+++ lua/ldebug.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,624 @@
+/*
+** $Id: ldebug.c,v 2.29.1.3 2007/12/28 15:32:23 roberto Exp $
+** Debug Interface
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+
+#define ldebug_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+
+
+static int currentpc (lua_State *L, CallInfo *ci) {
+  if (!isLua(ci)) return -1;  /* function is not a Lua function? */
+  if (ci == L->ci)
+    ci->savedpc = L->savedpc;
+  return pcRel(ci->savedpc, ci_func(ci)->l.p);
+}
+
+
+static int currentline (lua_State *L, CallInfo *ci) {
+  int pc = currentpc(L, ci);
+  if (pc < 0)
+    return -1;  /* only active lua functions have current-line information */
+  else
+    return getline(ci_func(ci)->l.p, pc);
+}
+
+
+/*
+** this function can be called asynchronous (e.g. during a signal)
+*/
+LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
+  if (func == NULL || mask == 0) {  /* turn off hooks? */
+    mask = 0;
+    func = NULL;
+  }
+  L->hook = func;
+  L->basehookcount = count;
+  resethookcount(L);
+  L->hookmask = cast_byte(mask);
+  return 1;
+}
+
+
+LUA_API lua_Hook lua_gethook (lua_State *L) {
+  return L->hook;
+}
+
+
+LUA_API int lua_gethookmask (lua_State *L) {
+  return L->hookmask;
+}
+
+
+LUA_API int lua_gethookcount (lua_State *L) {
+  return L->basehookcount;
+}
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
+  int status;
+  CallInfo *ci;
+  lua_lock(L);
+  for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
+    level--;
+    if (f_isLua(ci))  /* Lua function? */
+      level -= ci->tailcalls;  /* skip lost tail calls */
+  }
+  if (level == 0 && ci > L->base_ci) {  /* level found? */
+    status = 1;
+    ar->i_ci = cast_int(ci - L->base_ci);
+  }
+  else if (level < 0) {  /* level is of a lost tail call? */
+    status = 1;
+    ar->i_ci = 0;
+  }
+  else status = 0;  /* no such level */
+  lua_unlock(L);
+  return status;
+}
+
+
+static Proto *getluaproto (CallInfo *ci) {
+  return (isLua(ci) ? ci_func(ci)->l.p : NULL);
+}
+
+
+static const char *findlocal (lua_State *L, CallInfo *ci, int n) {
+  const char *name;
+  Proto *fp = getluaproto(ci);
+  if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL)
+    return name;  /* is a local variable in a Lua function */
+  else {
+    StkId limit = (ci == L->ci) ? L->top : (ci+1)->func;
+    if (limit - ci->base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
+      return "(*temporary)";
+    else
+      return NULL;
+  }
+}
+
+
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
+  CallInfo *ci = L->base_ci + ar->i_ci;
+  const char *name = findlocal(L, ci, n);
+  lua_lock(L);
+  if (name)
+      luaA_pushobject(L, ci->base + (n - 1));
+  lua_unlock(L);
+  return name;
+}
+
+
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
+  CallInfo *ci = L->base_ci + ar->i_ci;
+  const char *name = findlocal(L, ci, n);
+  lua_lock(L);
+  if (name)
+      setobjs2s(L, ci->base + (n - 1), L->top - 1);
+  L->top--;  /* pop value */
+  lua_unlock(L);
+  return name;
+}
+
+
+static void funcinfo (lua_Debug *ar, Closure *cl) {
+  if (cl->c.isC) {
+    ar->source = "=[C]";
+    ar->linedefined = -1;
+    ar->lastlinedefined = -1;
+    ar->what = "C";
+  }
+  else {
+    ar->source = getstr(cl->l.p->source);
+    ar->linedefined = cl->l.p->linedefined;
+    ar->lastlinedefined = cl->l.p->lastlinedefined;
+    ar->what = (ar->linedefined == 0) ? "main" : "Lua";
+  }
+  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+}
+
+
+static void info_tailcall (lua_Debug *ar) {
+  ar->name = ar->namewhat = "";
+  ar->what = "tail";
+  ar->lastlinedefined = ar->linedefined = ar->currentline = -1;
+  ar->source = "=(tail call)";
+  luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
+  ar->nups = 0;
+}
+
+
+static void collectvalidlines (lua_State *L, Closure *f) {
+  if (f == NULL || f->c.isC) {
+    setnilvalue(L->top);
+  }
+  else {
+    Table *t = luaH_new(L, 0, 0);
+    int *lineinfo = f->l.p->lineinfo;
+    int i;
+    for (i=0; i<f->l.p->sizelineinfo; i++)
+      setbvalue(luaH_setnum(L, t, lineinfo[i]), 1);
+    sethvalue(L, L->top, t); 
+  }
+  incr_top(L);
+}
+
+
+static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
+                    Closure *f, CallInfo *ci) {
+  int status = 1;
+  if (f == NULL) {
+    info_tailcall(ar);
+    return status;
+  }
+  for (; *what; what++) {
+    switch (*what) {
+      case 'S': {
+        funcinfo(ar, f);
+        break;
+      }
+      case 'l': {
+        ar->currentline = (ci) ? currentline(L, ci) : -1;
+        break;
+      }
+      case 'u': {
+        ar->nups = f->c.nupvalues;
+        break;
+      }
+      case 'n': {
+        ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
+        if (ar->namewhat == NULL) {
+          ar->namewhat = "";  /* not found */
+          ar->name = NULL;
+        }
+        break;
+      }
+      case 'L':
+      case 'f':  /* handled by lua_getinfo */
+        break;
+      default: status = 0;  /* invalid option */
+    }
+  }
+  return status;
+}
+
+
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
+  int status;
+  Closure *f = NULL;
+  CallInfo *ci = NULL;
+  lua_lock(L);
+  if (*what == '>') {
+    StkId func = L->top - 1;
+    luai_apicheck(L, ttisfunction(func));
+    what++;  /* skip the '>' */
+    f = clvalue(func);
+    L->top--;  /* pop function */
+  }
+  else if (ar->i_ci != 0) {  /* no tail call? */
+    ci = L->base_ci + ar->i_ci;
+    lua_assert(ttisfunction(ci->func));
+    f = clvalue(ci->func);
+  }
+  status = auxgetinfo(L, what, ar, f, ci);
+  if (strchr(what, 'f')) {
+    if (f == NULL) setnilvalue(L->top);
+    else setclvalue(L, L->top, f);
+    incr_top(L);
+  }
+  if (strchr(what, 'L'))
+    collectvalidlines(L, f);
+  lua_unlock(L);
+  return status;
+}
+
+
+/*
+** {======================================================
+** Symbolic Execution and code checker
+** =======================================================
+*/
+
+#define check(x)		if (!(x)) return 0;
+
+#define checkjump(pt,pc)	check(0 <= pc && pc < pt->sizecode)
+
+#define checkreg(pt,reg)	check((reg) < (pt)->maxstacksize)
+
+
+
+static int precheck (const Proto *pt) {
+  check(pt->maxstacksize <= MAXSTACK);
+  lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
+  lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) ||
+              (pt->is_vararg & VARARG_HASARG));
+  check(pt->sizeupvalues <= pt->nups);
+  check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
+  check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
+  return 1;
+}
+
+
+#define checkopenop(pt,pc)	luaG_checkopenop((pt)->code[(pc)+1])
+
+int luaG_checkopenop (Instruction i) {
+  switch (GET_OPCODE(i)) {
+    case OP_CALL:
+    case OP_TAILCALL:
+    case OP_RETURN:
+    case OP_SETLIST: {
+      check(GETARG_B(i) == 0);
+      return 1;
+    }
+    default: return 0;  /* invalid instruction after an open call */
+  }
+}
+
+
+static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) {
+  switch (mode) {
+    case OpArgN: check(r == 0); break;
+    case OpArgU: break;
+    case OpArgR: checkreg(pt, r); break;
+    case OpArgK:
+      check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize);
+      break;
+  }
+  return 1;
+}
+
+
+static Instruction symbexec (const Proto *pt, int lastpc, int reg) {
+  int pc;
+  int last;  /* stores position of last instruction that changed `reg' */
+  last = pt->sizecode-1;  /* points to final return (a `neutral' instruction) */
+  check(precheck(pt));
+  for (pc = 0; pc < lastpc; pc++) {
+    Instruction i = pt->code[pc];
+    OpCode op = GET_OPCODE(i);
+    int a = GETARG_A(i);
+    int b = 0;
+    int c = 0;
+    check(op < NUM_OPCODES);
+    checkreg(pt, a);
+    switch (getOpMode(op)) {
+      case iABC: {
+        b = GETARG_B(i);
+        c = GETARG_C(i);
+        check(checkArgMode(pt, b, getBMode(op)));
+        check(checkArgMode(pt, c, getCMode(op)));
+        break;
+      }
+      case iABx: {
+        b = GETARG_Bx(i);
+        if (getBMode(op) == OpArgK) check(b < pt->sizek);
+        break;
+      }
+      case iAsBx: {
+        b = GETARG_sBx(i);
+        if (getBMode(op) == OpArgR) {
+          int dest = pc+1+b;
+          check(0 <= dest && dest < pt->sizecode);
+          if (dest > 0) {
+            /* cannot jump to a setlist count */
+            Instruction d = pt->code[dest-1];
+            check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0));
+          }
+        }
+        break;
+      }
+    }
+    if (testAMode(op)) {
+      if (a == reg) last = pc;  /* change register `a' */
+    }
+    if (testTMode(op)) {
+      check(pc+2 < pt->sizecode);  /* check skip */
+      check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
+    }
+    switch (op) {
+      case OP_LOADBOOL: {
+        check(c == 0 || pc+2 < pt->sizecode);  /* check its jump */
+        break;
+      }
+      case OP_LOADNIL: {
+        if (a <= reg && reg <= b)
+          last = pc;  /* set registers from `a' to `b' */
+        break;
+      }
+      case OP_GETUPVAL:
+      case OP_SETUPVAL: {
+        check(b < pt->nups);
+        break;
+      }
+      case OP_GETGLOBAL:
+      case OP_SETGLOBAL: {
+        check(ttisstring(&pt->k[b]));
+        break;
+      }
+      case OP_SELF: {
+        checkreg(pt, a+1);
+        if (reg == a+1) last = pc;
+        break;
+      }
+      case OP_CONCAT: {
+        check(b < c);  /* at least two operands */
+        break;
+      }
+      case OP_TFORLOOP: {
+        check(c >= 1);  /* at least one result (control variable) */
+        checkreg(pt, a+2+c);  /* space for results */
+        if (reg >= a+2) last = pc;  /* affect all regs above its base */
+        break;
+      }
+      case OP_FORLOOP:
+      case OP_FORPREP:
+        checkreg(pt, a+3);
+        /* go through */
+      case OP_JMP: {
+        int dest = pc+1+b;
+        /* not full check and jump is forward and do not skip `lastpc'? */
+        if (reg != NO_REG && pc < dest && dest <= lastpc)
+          pc += b;  /* do the jump */
+        break;
+      }
+      case OP_CALL:
+      case OP_TAILCALL: {
+        if (b != 0) {
+          checkreg(pt, a+b-1);
+        }
+        c--;  /* c = num. returns */
+        if (c == LUA_MULTRET) {
+          check(checkopenop(pt, pc));
+        }
+        else if (c != 0)
+          checkreg(pt, a+c-1);
+        if (reg >= a) last = pc;  /* affect all registers above base */
+        break;
+      }
+      case OP_RETURN: {
+        b--;  /* b = num. returns */
+        if (b > 0) checkreg(pt, a+b-1);
+        break;
+      }
+      case OP_SETLIST: {
+        if (b > 0) checkreg(pt, a + b);
+        if (c == 0) pc++;
+        break;
+      }
+      case OP_CLOSURE: {
+        int nup, j;
+        check(b < pt->sizep);
+        nup = pt->p[b]->nups;
+        check(pc + nup < pt->sizecode);
+        for (j = 1; j <= nup; j++) {
+          OpCode op1 = GET_OPCODE(pt->code[pc + j]);
+          check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
+        }
+        if (reg != NO_REG)  /* tracing? */
+          pc += nup;  /* do not 'execute' these pseudo-instructions */
+        break;
+      }
+      case OP_VARARG: {
+        check((pt->is_vararg & VARARG_ISVARARG) &&
+             !(pt->is_vararg & VARARG_NEEDSARG));
+        b--;
+        if (b == LUA_MULTRET) check(checkopenop(pt, pc));
+        checkreg(pt, a+b-1);
+        break;
+      }
+      default: break;
+    }
+  }
+  return pt->code[last];
+}
+
+#undef check
+#undef checkjump
+#undef checkreg
+
+/* }====================================================== */
+
+
+int luaG_checkcode (const Proto *pt) {
+  return (symbexec(pt, pt->sizecode, NO_REG) != 0);
+}
+
+
+static const char *kname (Proto *p, int c) {
+  if (ISK(c) && ttisstring(&p->k[INDEXK(c)]))
+    return svalue(&p->k[INDEXK(c)]);
+  else
+    return "?";
+}
+
+
+static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos,
+                               const char **name) {
+  if (isLua(ci)) {  /* a Lua function? */
+    Proto *p = ci_func(ci)->l.p;
+    int pc = currentpc(L, ci);
+    Instruction i;
+    *name = luaF_getlocalname(p, stackpos+1, pc);
+    if (*name)  /* is a local? */
+      return "local";
+    i = symbexec(p, pc, stackpos);  /* try symbolic execution */
+    lua_assert(pc != -1);
+    switch (GET_OPCODE(i)) {
+      case OP_GETGLOBAL: {
+        int g = GETARG_Bx(i);  /* global index */
+        lua_assert(ttisstring(&p->k[g]));
+        *name = svalue(&p->k[g]);
+        return "global";
+      }
+      case OP_MOVE: {
+        int a = GETARG_A(i);
+        int b = GETARG_B(i);  /* move from `b' to `a' */
+        if (b < a)
+          return getobjname(L, ci, b, name);  /* get name for `b' */
+        break;
+      }
+      case OP_GETTABLE: {
+        int k = GETARG_C(i);  /* key index */
+        *name = kname(p, k);
+        return "field";
+      }
+      case OP_GETUPVAL: {
+        int u = GETARG_B(i);  /* upvalue index */
+        *name = p->upvalues ? getstr(p->upvalues[u]) : "?";
+        return "upvalue";
+      }
+      case OP_SELF: {
+        int k = GETARG_C(i);  /* key index */
+        *name = kname(p, k);
+        return "method";
+      }
+      default: break;
+    }
+  }
+  return NULL;  /* no useful name found */
+}
+
+
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+  Instruction i;
+  if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1))
+    return NULL;  /* calling function is not Lua (or is unknown) */
+  ci--;  /* calling function */
+  i = ci_func(ci)->l.p->code[currentpc(L, ci)];
+  if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL ||
+      GET_OPCODE(i) == OP_TFORLOOP)
+    return getobjname(L, ci, GETARG_A(i), name);
+  else
+    return NULL;  /* no useful name can be found */
+}
+
+
+/* only ANSI way to check whether a pointer points to an array */
+static int isinstack (CallInfo *ci, const TValue *o) {
+  StkId p;
+  for (p = ci->base; p < ci->top; p++)
+    if (o == p) return 1;
+  return 0;
+}
+
+
+void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
+  const char *name = NULL;
+  const char *t = luaT_typenames[ttype(o)];
+  const char *kind = (isinstack(L->ci, o)) ?
+                         getobjname(L, L->ci, cast_int(o - L->base), &name) :
+                         NULL;
+  if (kind)
+    luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
+                op, kind, name, t);
+  else
+    luaG_runerror(L, "attempt to %s a %s value", op, t);
+}
+
+
+void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
+  if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
+  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
+  luaG_typeerror(L, p1, "concatenate");
+}
+
+
+void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
+  TValue temp;
+  if (luaV_tonumber(p1, &temp) == NULL)
+    p2 = p1;  /* first operand is wrong */
+  luaG_typeerror(L, p2, "perform arithmetic on");
+}
+
+
+int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
+  const char *t1 = luaT_typenames[ttype(p1)];
+  const char *t2 = luaT_typenames[ttype(p2)];
+  if (t1[2] == t2[2])
+    luaG_runerror(L, "attempt to compare two %s values", t1);
+  else
+    luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
+  return 0;
+}
+
+
+static void addinfo (lua_State *L, const char *msg) {
+  CallInfo *ci = L->ci;
+  if (isLua(ci)) {  /* is Lua code? */
+    char buff[LUA_IDSIZE];  /* add file:line information */
+    int line = currentline(L, ci);
+    luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
+    luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+  }
+}
+
+
+void luaG_errormsg (lua_State *L) {
+  if (L->errfunc != 0) {  /* is there an error handling function? */
+    StkId errfunc = restorestack(L, L->errfunc);
+    if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
+    setobjs2s(L, L->top, L->top - 1);  /* move argument */
+    setobjs2s(L, L->top - 1, errfunc);  /* push function */
+    incr_top(L);
+    luaD_call(L, L->top - 2, 1);  /* call it */
+  }
+  luaD_throw(L, LUA_ERRRUN);
+}
+
+
+void luaG_runerror (lua_State *L, const char *fmt, ...) {
+  va_list argp;
+  va_start(argp, fmt);
+  addinfo(L, luaO_pushvfstring(L, fmt, argp));
+  va_end(argp);
+  luaG_errormsg(L);
+}
+

=== added file 'lua/ldebug.h'
--- lua/ldebug.h	1970-01-01 00:00:00 +0000
+++ lua/ldebug.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,33 @@
+/*
+** $Id: ldebug.h,v 2.3.1.1 2007/12/27 13:02:25 roberto Exp $
+** Auxiliary functions from Debug Interface module
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldebug_h
+#define ldebug_h
+
+
+#include "lstate.h"
+
+
+#define pcRel(pc, p)	(cast(int, (pc) - (p)->code) - 1)
+
+#define getline(f,pc)	(((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
+
+#define resethookcount(L)	(L->hookcount = L->basehookcount)
+
+
+LUAI_FUNC void luaG_typeerror (lua_State *L, const TValue *o,
+                                             const char *opname);
+LUAI_FUNC void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
+LUAI_FUNC void luaG_aritherror (lua_State *L, const TValue *p1,
+                                              const TValue *p2);
+LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1,
+                                             const TValue *p2);
+LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...);
+LUAI_FUNC void luaG_errormsg (lua_State *L);
+LUAI_FUNC int luaG_checkcode (const Proto *pt);
+LUAI_FUNC int luaG_checkopenop (Instruction i);
+
+#endif

=== added file 'lua/ldo.c'
--- lua/ldo.c	1970-01-01 00:00:00 +0000
+++ lua/ldo.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,520 @@
+/*
+** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <setjmp.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define ldo_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lundump.h"
+#include "lvm.h"
+#include "lzio.h"
+
+
+
+
+/*
+** {======================================================
+** Error-recovery functions
+** =======================================================
+*/
+
+
+/* chain list of long jump buffers */
+struct lua_longjmp {
+  struct lua_longjmp *previous;
+  luai_jmpbuf b;
+  volatile int status;  /* error code */
+};
+
+
+void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
+  switch (errcode) {
+    case LUA_ERRMEM: {
+      setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG));
+      break;
+    }
+    case LUA_ERRERR: {
+      setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
+      break;
+    }
+    case LUA_ERRSYNTAX:
+    case LUA_ERRRUN: {
+      setobjs2s(L, oldtop, L->top - 1);  /* error message on current top */
+      break;
+    }
+  }
+  L->top = oldtop + 1;
+}
+
+
+static void restore_stack_limit (lua_State *L) {
+  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
+  if (L->size_ci > LUAI_MAXCALLS) {  /* there was an overflow? */
+    int inuse = cast_int(L->ci - L->base_ci);
+    if (inuse + 1 < LUAI_MAXCALLS)  /* can `undo' overflow? */
+      luaD_reallocCI(L, LUAI_MAXCALLS);
+  }
+}
+
+
+static void resetstack (lua_State *L, int status) {
+  L->ci = L->base_ci;
+  L->base = L->ci->base;
+  luaF_close(L, L->base);  /* close eventual pending closures */
+  luaD_seterrorobj(L, status, L->base);
+  L->nCcalls = L->baseCcalls;
+  L->allowhook = 1;
+  restore_stack_limit(L);
+  L->errfunc = 0;
+  L->errorJmp = NULL;
+}
+
+
+void luaD_throw (lua_State *L, int errcode) {
+  if (L->errorJmp) {
+    L->errorJmp->status = errcode;
+    LUAI_THROW(L, L->errorJmp);
+  }
+  else {
+    L->status = cast_byte(errcode);
+    if (G(L)->panic) {
+      resetstack(L, errcode);
+      lua_unlock(L);
+      G(L)->panic(L);
+    }
+    exit(EXIT_FAILURE);
+  }
+}
+
+
+int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
+  struct lua_longjmp lj;
+  lj.status = 0;
+  lj.previous = L->errorJmp;  /* chain new error handler */
+  L->errorJmp = &lj;
+  LUAI_TRY(L, &lj,
+    (*f)(L, ud);
+  );
+  L->errorJmp = lj.previous;  /* restore old error handler */
+  return lj.status;
+}
+
+/* }====================================================== */
+
+
+static void correctstack (lua_State *L, TValue *oldstack) {
+  CallInfo *ci;
+  GCObject *up;
+  L->top = (L->top - oldstack) + L->stack;
+  for (up = L->openupval; up != NULL; up = up->gch.next)
+    gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
+  for (ci = L->base_ci; ci <= L->ci; ci++) {
+    ci->top = (ci->top - oldstack) + L->stack;
+    ci->base = (ci->base - oldstack) + L->stack;
+    ci->func = (ci->func - oldstack) + L->stack;
+  }
+  L->base = (L->base - oldstack) + L->stack;
+}
+
+
+void luaD_reallocstack (lua_State *L, int newsize) {
+  TValue *oldstack = L->stack;
+  int realsize = newsize + 1 + EXTRA_STACK;
+  lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
+  luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
+  L->stacksize = realsize;
+  L->stack_last = L->stack+newsize;
+  correctstack(L, oldstack);
+}
+
+
+void luaD_reallocCI (lua_State *L, int newsize) {
+  CallInfo *oldci = L->base_ci;
+  luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
+  L->size_ci = newsize;
+  L->ci = (L->ci - oldci) + L->base_ci;
+  L->end_ci = L->base_ci + L->size_ci - 1;
+}
+
+
+void luaD_growstack (lua_State *L, int n) {
+  if (n <= L->stacksize)  /* double size is enough? */
+    luaD_reallocstack(L, 2*L->stacksize);
+  else
+    luaD_reallocstack(L, L->stacksize + n);
+}
+
+
+static CallInfo *growCI (lua_State *L) {
+  if (L->size_ci > LUAI_MAXCALLS)  /* overflow while handling overflow? */
+    luaD_throw(L, LUA_ERRERR);
+  else {
+    luaD_reallocCI(L, 2*L->size_ci);
+    if (L->size_ci > LUAI_MAXCALLS)
+      luaG_runerror(L, "stack overflow");
+  }
+  return ++L->ci;
+}
+
+
+void luaD_callhook (lua_State *L, int event, int line) {
+  lua_Hook hook = L->hook;
+  if (hook && L->allowhook) {
+    ptrdiff_t top = savestack(L, L->top);
+    ptrdiff_t ci_top = savestack(L, L->ci->top);
+    lua_Debug ar;
+    ar.event = event;
+    ar.currentline = line;
+    if (event == LUA_HOOKTAILRET)
+      ar.i_ci = 0;  /* tail call; no debug information about it */
+    else
+      ar.i_ci = cast_int(L->ci - L->base_ci);
+    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+    L->ci->top = L->top + LUA_MINSTACK;
+    lua_assert(L->ci->top <= L->stack_last);
+    L->allowhook = 0;  /* cannot call hooks inside a hook */
+    lua_unlock(L);
+    (*hook)(L, &ar);
+    lua_lock(L);
+    lua_assert(!L->allowhook);
+    L->allowhook = 1;
+    L->ci->top = restorestack(L, ci_top);
+    L->top = restorestack(L, top);
+  }
+}
+
+
+static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
+  int i;
+  int nfixargs = p->numparams;
+  Table *htab = NULL;
+  StkId base, fixed;
+  for (; actual < nfixargs; ++actual)
+    setnilvalue(L->top++);
+#if defined(LUA_COMPAT_VARARG)
+  if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */
+    int nvar = actual - nfixargs;  /* number of extra arguments */
+    lua_assert(p->is_vararg & VARARG_HASARG);
+    luaC_checkGC(L);
+    htab = luaH_new(L, nvar, 1);  /* create `arg' table */
+    for (i=0; i<nvar; i++)  /* put extra arguments into `arg' table */
+      setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
+    /* store counter in field `n' */
+    setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar));
+  }
+#endif
+  /* move fixed parameters to final position */
+  fixed = L->top - actual;  /* first fixed argument */
+  base = L->top;  /* final position of first argument */
+  for (i=0; i<nfixargs; i++) {
+    setobjs2s(L, L->top++, fixed+i);
+    setnilvalue(fixed+i);
+  }
+  /* add `arg' parameter */
+  if (htab) {
+    sethvalue(L, L->top++, htab);
+    lua_assert(iswhite(obj2gco(htab)));
+  }
+  return base;
+}
+
+
+static StkId tryfuncTM (lua_State *L, StkId func) {
+  const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
+  StkId p;
+  ptrdiff_t funcr = savestack(L, func);
+  if (!ttisfunction(tm))
+    luaG_typeerror(L, func, "call");
+  /* Open a hole inside the stack at `func' */
+  for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
+  incr_top(L);
+  func = restorestack(L, funcr);  /* previous call may change stack */
+  setobj2s(L, func, tm);  /* tag method is the new function to be called */
+  return func;
+}
+
+
+
+#define inc_ci(L) \
+  ((L->ci == L->end_ci) ? growCI(L) : \
+   (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci))
+
+
+int luaD_precall (lua_State *L, StkId func, int nresults) {
+  LClosure *cl;
+  ptrdiff_t funcr;
+  if (!ttisfunction(func)) /* `func' is not a function? */
+    func = tryfuncTM(L, func);  /* check the `function' tag method */
+  funcr = savestack(L, func);
+  cl = &clvalue(func)->l;
+  L->ci->savedpc = L->savedpc;
+  if (!cl->isC) {  /* Lua function? prepare its call */
+    CallInfo *ci;
+    StkId st, base;
+    Proto *p = cl->p;
+    luaD_checkstack(L, p->maxstacksize);
+    func = restorestack(L, funcr);
+    if (!p->is_vararg) {  /* no varargs? */
+      base = func + 1;
+      if (L->top > base + p->numparams)
+        L->top = base + p->numparams;
+    }
+    else {  /* vararg function */
+      int nargs = cast_int(L->top - func) - 1;
+      base = adjust_varargs(L, p, nargs);
+      func = restorestack(L, funcr);  /* previous call may change the stack */
+    }
+    ci = inc_ci(L);  /* now `enter' new function */
+    ci->func = func;
+    L->base = ci->base = base;
+    ci->top = L->base + p->maxstacksize;
+    lua_assert(ci->top <= L->stack_last);
+    L->savedpc = p->code;  /* starting point */
+    ci->tailcalls = 0;
+    ci->nresults = nresults;
+    for (st = L->top; st < ci->top; st++)
+      setnilvalue(st);
+    L->top = ci->top;
+    if (L->hookmask & LUA_MASKCALL) {
+      L->savedpc++;  /* hooks assume 'pc' is already incremented */
+      luaD_callhook(L, LUA_HOOKCALL, -1);
+      L->savedpc--;  /* correct 'pc' */
+    }
+    return PCRLUA;
+  }
+  else {  /* if is a C function, call it */
+    CallInfo *ci;
+    int n;
+    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+    ci = inc_ci(L);  /* now `enter' new function */
+    ci->func = restorestack(L, funcr);
+    L->base = ci->base = ci->func + 1;
+    ci->top = L->top + LUA_MINSTACK;
+    lua_assert(ci->top <= L->stack_last);
+    ci->nresults = nresults;
+    if (L->hookmask & LUA_MASKCALL)
+      luaD_callhook(L, LUA_HOOKCALL, -1);
+    lua_unlock(L);
+    n = (*curr_func(L)->c.f)(L);  /* do the actual call */
+    lua_lock(L);
+    if (n < 0)  /* yielding? */
+      return PCRYIELD;
+    else {
+      luaD_poscall(L, L->top - n);
+      return PCRC;
+    }
+  }
+}
+
+
+static StkId callrethooks (lua_State *L, StkId firstResult) {
+  ptrdiff_t fr = savestack(L, firstResult);  /* next call may change stack */
+  luaD_callhook(L, LUA_HOOKRET, -1);
+  if (f_isLua(L->ci)) {  /* Lua function? */
+    while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */
+      luaD_callhook(L, LUA_HOOKTAILRET, -1);
+  }
+  return restorestack(L, fr);
+}
+
+
+int luaD_poscall (lua_State *L, StkId firstResult) {
+  StkId res;
+  int wanted, i;
+  CallInfo *ci;
+  if (L->hookmask & LUA_MASKRET)
+    firstResult = callrethooks(L, firstResult);
+  ci = L->ci--;
+  res = ci->func;  /* res == final position of 1st result */
+  wanted = ci->nresults;
+  L->base = (ci - 1)->base;  /* restore base */
+  L->savedpc = (ci - 1)->savedpc;  /* restore savedpc */
+  /* move results to correct place */
+  for (i = wanted; i != 0 && firstResult < L->top; i--)
+    setobjs2s(L, res++, firstResult++);
+  while (i-- > 0)
+    setnilvalue(res++);
+  L->top = res;
+  return (wanted - LUA_MULTRET);  /* 0 iff wanted == LUA_MULTRET */
+}
+
+
+/*
+** Call a function (C or Lua). The function to be called is at *func.
+** The arguments are on the stack, right after the function.
+** When returns, all the results are on the stack, starting at the original
+** function position.
+*/ 
+void luaD_call (lua_State *L, StkId func, int nResults) {
+  if (++L->nCcalls >= LUAI_MAXCCALLS) {
+    if (L->nCcalls == LUAI_MAXCCALLS)
+      luaG_runerror(L, "C stack overflow");
+    else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
+      luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
+  }
+  if (luaD_precall(L, func, nResults) == PCRLUA)  /* is a Lua function? */
+    luaV_execute(L, 1);  /* call it */
+  L->nCcalls--;
+  luaC_checkGC(L);
+}
+
+
+static void resume (lua_State *L, void *ud) {
+  StkId firstArg = cast(StkId, ud);
+  CallInfo *ci = L->ci;
+  if (L->status == 0) {  /* start coroutine? */
+    lua_assert(ci == L->base_ci && firstArg > L->base);
+    if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA)
+      return;
+  }
+  else {  /* resuming from previous yield */
+    lua_assert(L->status == LUA_YIELD);
+    L->status = 0;
+    if (!f_isLua(ci)) {  /* `common' yield? */
+      /* finish interrupted execution of `OP_CALL' */
+      lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
+                 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
+      if (luaD_poscall(L, firstArg))  /* complete it... */
+        L->top = L->ci->top;  /* and correct top if not multiple results */
+    }
+    else  /* yielded inside a hook: just continue its execution */
+      L->base = L->ci->base;
+  }
+  luaV_execute(L, cast_int(L->ci - L->base_ci));
+}
+
+
+static int resume_error (lua_State *L, const char *msg) {
+  L->top = L->ci->base;
+  setsvalue2s(L, L->top, luaS_new(L, msg));
+  incr_top(L);
+  lua_unlock(L);
+  return LUA_ERRRUN;
+}
+
+
+LUA_API int lua_resume (lua_State *L, int nargs) {
+  int status;
+  lua_lock(L);
+  if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
+      return resume_error(L, "cannot resume non-suspended coroutine");
+  if (L->nCcalls >= LUAI_MAXCCALLS)
+    return resume_error(L, "C stack overflow");
+  luai_userstateresume(L, nargs);
+  lua_assert(L->errfunc == 0);
+  L->baseCcalls = ++L->nCcalls;
+  status = luaD_rawrunprotected(L, resume, L->top - nargs);
+  if (status != 0) {  /* error? */
+    L->status = cast_byte(status);  /* mark thread as `dead' */
+    luaD_seterrorobj(L, status, L->top);
+    L->ci->top = L->top;
+  }
+  else {
+    lua_assert(L->nCcalls == L->baseCcalls);
+    status = L->status;
+  }
+  --L->nCcalls;
+  lua_unlock(L);
+  return status;
+}
+
+
+LUA_API int lua_yield (lua_State *L, int nresults) {
+  luai_userstateyield(L, nresults);
+  lua_lock(L);
+  if (L->nCcalls > L->baseCcalls)
+    luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
+  L->base = L->top - nresults;  /* protect stack slots below */
+  L->status = LUA_YIELD;
+  lua_unlock(L);
+  return -1;
+}
+
+
+int luaD_pcall (lua_State *L, Pfunc func, void *u,
+                ptrdiff_t old_top, ptrdiff_t ef) {
+  int status;
+  unsigned short oldnCcalls = L->nCcalls;
+  ptrdiff_t old_ci = saveci(L, L->ci);
+  lu_byte old_allowhooks = L->allowhook;
+  ptrdiff_t old_errfunc = L->errfunc;
+  L->errfunc = ef;
+  status = luaD_rawrunprotected(L, func, u);
+  if (status != 0) {  /* an error occurred? */
+    StkId oldtop = restorestack(L, old_top);
+    luaF_close(L, oldtop);  /* close eventual pending closures */
+    luaD_seterrorobj(L, status, oldtop);
+    L->nCcalls = oldnCcalls;
+    L->ci = restoreci(L, old_ci);
+    L->base = L->ci->base;
+    L->savedpc = L->ci->savedpc;
+    L->allowhook = old_allowhooks;
+    restore_stack_limit(L);
+  }
+  L->errfunc = old_errfunc;
+  return status;
+}
+
+
+
+/*
+** Execute a protected parser.
+*/
+struct SParser {  /* data to `f_parser' */
+  ZIO *z;
+  Mbuffer buff;  /* buffer to be used by the scanner */
+  const char *name;
+};
+
+static void f_parser (lua_State *L, void *ud) {
+  int i;
+  Proto *tf;
+  Closure *cl;
+  struct SParser *p = cast(struct SParser *, ud);
+  int c = luaZ_lookahead(p->z);
+  luaC_checkGC(L);
+  tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
+                                                             &p->buff, p->name);
+  cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
+  cl->l.p = tf;
+  for (i = 0; i < tf->nups; i++)  /* initialize eventual upvalues */
+    cl->l.upvals[i] = luaF_newupval(L);
+  setclvalue(L, L->top, cl);
+  incr_top(L);
+}
+
+
+int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) {
+  struct SParser p;
+  int status;
+  p.z = z; p.name = name;
+  luaZ_initbuffer(L, &p.buff);
+  status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+  luaZ_freebuffer(L, &p.buff);
+  return status;
+}
+
+

=== added file 'lua/ldo.h'
--- lua/ldo.h	1970-01-01 00:00:00 +0000
+++ lua/ldo.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,57 @@
+/*
+** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $
+** Stack and Call structure of Lua
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ldo_h
+#define ldo_h
+
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lzio.h"
+
+
+#define luaD_checkstack(L,n)	\
+  if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \
+    luaD_growstack(L, n); \
+  else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1));
+
+
+#define incr_top(L) {luaD_checkstack(L,1); L->top++;}
+
+#define savestack(L,p)		((char *)(p) - (char *)L->stack)
+#define restorestack(L,n)	((TValue *)((char *)L->stack + (n)))
+
+#define saveci(L,p)		((char *)(p) - (char *)L->base_ci)
+#define restoreci(L,n)		((CallInfo *)((char *)L->base_ci + (n)))
+
+
+/* results from luaD_precall */
+#define PCRLUA		0	/* initiated a call to a Lua function */
+#define PCRC		1	/* did a call to a C function */
+#define PCRYIELD	2	/* C funtion yielded */
+
+
+/* type of protected functions, to be ran by `runprotected' */
+typedef void (*Pfunc) (lua_State *L, void *ud);
+
+LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
+LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
+LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
+LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
+LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
+                                        ptrdiff_t oldtop, ptrdiff_t ef);
+LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
+LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize);
+LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
+LUAI_FUNC void luaD_growstack (lua_State *L, int n);
+
+LUAI_FUNC void luaD_throw (lua_State *L, int errcode);
+LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
+
+LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
+
+#endif
+

=== added file 'lua/ldump.c'
--- lua/ldump.c	1970-01-01 00:00:00 +0000
+++ lua/ldump.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,166 @@
+/*
+** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** save precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef USE_GRUB_LIB
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+
+typedef struct {
+ lua_State* L;
+ lua_Writer writer;
+ void* data;
+ int strip;
+ int status;
+} DumpState;
+
+#define DumpMem(b,n,size,D)	DumpBlock(b,(n)*(size),D)
+#define DumpVar(x,D)	 	DumpMem(&x,1,sizeof(x),D)
+
+static void DumpBlock(const void* b, size_t size, DumpState* D)
+{
+ if (D->status==0)
+ {
+  lua_unlock(D->L);
+  D->status=(*D->writer)(D->L,b,size,D->data);
+  lua_lock(D->L);
+ }
+}
+
+static void DumpChar(int y, DumpState* D)
+{
+ char x=(char)y;
+ DumpVar(x,D);
+}
+
+static void DumpInt(int x, DumpState* D)
+{
+ DumpVar(x,D);
+}
+
+static void DumpNumber(lua_Number x, DumpState* D)
+{
+ DumpVar(x,D);
+}
+
+static void DumpVector(const void* b, int n, size_t size, DumpState* D)
+{
+ DumpInt(n,D);
+ DumpMem(b,n,size,D);
+}
+
+static void DumpString(const TString* s, DumpState* D)
+{
+ if (s==NULL || getstr(s)==NULL)
+ {
+  size_t size=0;
+  DumpVar(size,D);
+ }
+ else
+ {
+  size_t size=s->tsv.len+1;		/* include trailing '\0' */
+  DumpVar(size,D);
+  DumpBlock(getstr(s),size,D);
+ }
+}
+
+#define DumpCode(f,D)	 DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
+
+static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
+
+static void DumpConstants(const Proto* f, DumpState* D)
+{
+ int i,n=f->sizek;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+  const TValue* o=&f->k[i];
+  DumpChar(ttype(o),D);
+  switch (ttype(o))
+  {
+   case LUA_TNIL:
+	break;
+   case LUA_TBOOLEAN:
+	DumpChar(bvalue(o),D);
+	break;
+   case LUA_TNUMBER:
+	DumpNumber(nvalue(o),D);
+	break;
+   case LUA_TSTRING:
+	DumpString(rawtsvalue(o),D);
+	break;
+   default:
+	lua_assert(0);			/* cannot happen */
+	break;
+  }
+ }
+ n=f->sizep;
+ DumpInt(n,D);
+ for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
+}
+
+static void DumpDebug(const Proto* f, DumpState* D)
+{
+ int i,n;
+ n= (D->strip) ? 0 : f->sizelineinfo;
+ DumpVector(f->lineinfo,n,sizeof(int),D);
+ n= (D->strip) ? 0 : f->sizelocvars;
+ DumpInt(n,D);
+ for (i=0; i<n; i++)
+ {
+  DumpString(f->locvars[i].varname,D);
+  DumpInt(f->locvars[i].startpc,D);
+  DumpInt(f->locvars[i].endpc,D);
+ }
+ n= (D->strip) ? 0 : f->sizeupvalues;
+ DumpInt(n,D);
+ for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
+}
+
+static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
+{
+ DumpString((f->source==p || D->strip) ? NULL : f->source,D);
+ DumpInt(f->linedefined,D);
+ DumpInt(f->lastlinedefined,D);
+ DumpChar(f->nups,D);
+ DumpChar(f->numparams,D);
+ DumpChar(f->is_vararg,D);
+ DumpChar(f->maxstacksize,D);
+ DumpCode(f,D);
+ DumpConstants(f,D);
+ DumpDebug(f,D);
+}
+
+static void DumpHeader(DumpState* D)
+{
+ char h[LUAC_HEADERSIZE];
+ luaU_header(h);
+ DumpBlock(h,LUAC_HEADERSIZE,D);
+}
+
+/*
+** dump Lua function as precompiled chunk
+*/
+int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
+{
+ DumpState D;
+ D.L=L;
+ D.writer=w;
+ D.data=data;
+ D.strip=strip;
+ D.status=0;
+ DumpHeader(&D);
+ DumpFunction(f,NULL,&D);
+ return D.status;
+}

=== added file 'lua/lfunc.c'
--- lua/lfunc.c	1970-01-01 00:00:00 +0000
+++ lua/lfunc.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,176 @@
+/*
+** $Id: lfunc.c,v 2.12.1.2 2007/12/28 14:58:43 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lfunc_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e) {
+  Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
+  luaC_link(L, obj2gco(c), LUA_TFUNCTION);
+  c->c.isC = 1;
+  c->c.env = e;
+  c->c.nupvalues = cast_byte(nelems);
+  return c;
+}
+
+
+Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e) {
+  Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
+  luaC_link(L, obj2gco(c), LUA_TFUNCTION);
+  c->l.isC = 0;
+  c->l.env = e;
+  c->l.nupvalues = cast_byte(nelems);
+  while (nelems--) c->l.upvals[nelems] = NULL;
+  return c;
+}
+
+
+UpVal *luaF_newupval (lua_State *L) {
+  UpVal *uv = luaM_new(L, UpVal);
+  luaC_link(L, obj2gco(uv), LUA_TUPVAL);
+  uv->v = &uv->u.value;
+  setnilvalue(uv->v);
+  return uv;
+}
+
+
+UpVal *luaF_findupval (lua_State *L, StkId level) {
+  global_State *g = G(L);
+  GCObject **pp = &L->openupval;
+  UpVal *p;
+  UpVal *uv;
+  while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) {
+    lua_assert(p->v != &p->u.value);
+    if (p->v == level) {  /* found a corresponding upvalue? */
+      if (isdead(g, obj2gco(p)))  /* is it dead? */
+        changewhite(obj2gco(p));  /* ressurect it */
+      return p;
+    }
+    pp = &p->next;
+  }
+  uv = luaM_new(L, UpVal);  /* not found: create a new one */
+  uv->tt = LUA_TUPVAL;
+  uv->marked = luaC_white(g);
+  uv->v = level;  /* current value lives in the stack */
+  uv->next = *pp;  /* chain it in the proper position */
+  *pp = obj2gco(uv);
+  uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
+  uv->u.l.next = g->uvhead.u.l.next;
+  uv->u.l.next->u.l.prev = uv;
+  g->uvhead.u.l.next = uv;
+  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+  return uv;
+}
+
+
+static void unlinkupval (UpVal *uv) {
+  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+  uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */
+  uv->u.l.prev->u.l.next = uv->u.l.next;
+}
+
+
+void luaF_freeupval (lua_State *L, UpVal *uv) {
+  if (uv->v != &uv->u.value)  /* is it open? */
+    unlinkupval(uv);  /* remove from open list */
+  luaM_free(L, uv);  /* free upvalue */
+}
+
+
+void luaF_close (lua_State *L, StkId level) {
+  UpVal *uv;
+  global_State *g = G(L);
+  while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
+    GCObject *o = obj2gco(uv);
+    lua_assert(!isblack(o) && uv->v != &uv->u.value);
+    L->openupval = uv->next;  /* remove from `open' list */
+    if (isdead(g, o))
+      luaF_freeupval(L, uv);  /* free upvalue */
+    else {
+      unlinkupval(uv);
+      setobj(L, &uv->u.value, uv->v);
+      uv->v = &uv->u.value;  /* now current value lives here */
+      luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */
+    }
+  }
+}
+
+
+Proto *luaF_newproto (lua_State *L) {
+  Proto *f = luaM_new(L, Proto);
+  luaC_link(L, obj2gco(f), LUA_TPROTO);
+  f->k = NULL;
+  f->sizek = 0;
+  f->p = NULL;
+  f->sizep = 0;
+  f->code = NULL;
+  f->sizecode = 0;
+  f->sizelineinfo = 0;
+  f->sizeupvalues = 0;
+  f->nups = 0;
+  f->upvalues = NULL;
+  f->numparams = 0;
+  f->is_vararg = 0;
+  f->maxstacksize = 0;
+  f->lineinfo = NULL;
+  f->sizelocvars = 0;
+  f->locvars = NULL;
+  f->linedefined = 0;
+  f->lastlinedefined = 0;
+  f->source = NULL;
+  return f;
+}
+
+
+void luaF_freeproto (lua_State *L, Proto *f) {
+  luaM_freearray(L, f->code, f->sizecode, Instruction);
+  luaM_freearray(L, f->p, f->sizep, Proto *);
+  luaM_freearray(L, f->k, f->sizek, TValue);
+  luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
+  luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
+  luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
+  luaM_free(L, f);
+}
+
+
+void luaF_freeclosure (lua_State *L, Closure *c) {
+  int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
+                          sizeLclosure(c->l.nupvalues);
+  luaM_freemem(L, c, size);
+}
+
+
+/*
+** Look for n-th local variable at line `line' in function `func'.
+** Returns NULL if not found.
+*/
+const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
+  int i;
+  for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
+    if (pc < f->locvars[i].endpc) {  /* is variable active? */
+      local_number--;
+      if (local_number == 0)
+        return getstr(f->locvars[i].varname);
+    }
+  }
+  return NULL;  /* not found */
+}
+

=== added file 'lua/lfunc.h'
--- lua/lfunc.h	1970-01-01 00:00:00 +0000
+++ lua/lfunc.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,34 @@
+/*
+** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $
+** Auxiliary functions to manipulate prototypes and closures
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lfunc_h
+#define lfunc_h
+
+
+#include "lobject.h"
+
+
+#define sizeCclosure(n)	(cast(int, sizeof(CClosure)) + \
+                         cast(int, sizeof(TValue)*((n)-1)))
+
+#define sizeLclosure(n)	(cast(int, sizeof(LClosure)) + \
+                         cast(int, sizeof(TValue *)*((n)-1)))
+
+
+LUAI_FUNC Proto *luaF_newproto (lua_State *L);
+LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e);
+LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e);
+LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
+LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
+LUAI_FUNC void luaF_close (lua_State *L, StkId level);
+LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
+LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
+LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
+LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
+                                         int pc);
+
+
+#endif

=== added file 'lua/lgc.c'
--- lua/lgc.c	1970-01-01 00:00:00 +0000
+++ lua/lgc.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,713 @@
+/*
+** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lgc_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+#define GCSTEPSIZE	1024u
+#define GCSWEEPMAX	40
+#define GCSWEEPCOST	10
+#define GCFINALIZECOST	100
+
+
+#define maskmarks	cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
+
+#define makewhite(g,x)	\
+   ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
+
+#define white2gray(x)	reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
+#define black2gray(x)	resetbit((x)->gch.marked, BLACKBIT)
+
+#define stringmark(s)	reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
+
+
+#define isfinalized(u)		testbit((u)->marked, FINALIZEDBIT)
+#define markfinalized(u)	l_setbit((u)->marked, FINALIZEDBIT)
+
+
+#define KEYWEAK         bitmask(KEYWEAKBIT)
+#define VALUEWEAK       bitmask(VALUEWEAKBIT)
+
+
+
+#define markvalue(g,o) { checkconsistency(o); \
+  if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
+
+#define markobject(g,t) { if (iswhite(obj2gco(t))) \
+		reallymarkobject(g, obj2gco(t)); }
+
+
+#define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause)
+
+
+static void removeentry (Node *n) {
+  lua_assert(ttisnil(gval(n)));
+  if (iscollectable(gkey(n)))
+    setttype(gkey(n), LUA_TDEADKEY);  /* dead key; remove it */
+}
+
+
+static void reallymarkobject (global_State *g, GCObject *o) {
+  lua_assert(iswhite(o) && !isdead(g, o));
+  white2gray(o);
+  switch (o->gch.tt) {
+    case LUA_TSTRING: {
+      return;
+    }
+    case LUA_TUSERDATA: {
+      Table *mt = gco2u(o)->metatable;
+      gray2black(o);  /* udata are never gray */
+      if (mt) markobject(g, mt);
+      markobject(g, gco2u(o)->env);
+      return;
+    }
+    case LUA_TUPVAL: {
+      UpVal *uv = gco2uv(o);
+      markvalue(g, uv->v);
+      if (uv->v == &uv->u.value)  /* closed? */
+        gray2black(o);  /* open upvalues are never black */
+      return;
+    }
+    case LUA_TFUNCTION: {
+      gco2cl(o)->c.gclist = g->gray;
+      g->gray = o;
+      break;
+    }
+    case LUA_TTABLE: {
+      gco2h(o)->gclist = g->gray;
+      g->gray = o;
+      break;
+    }
+    case LUA_TTHREAD: {
+      gco2th(o)->gclist = g->gray;
+      g->gray = o;
+      break;
+    }
+    case LUA_TPROTO: {
+      gco2p(o)->gclist = g->gray;
+      g->gray = o;
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+static void marktmu (global_State *g) {
+  GCObject *u = g->tmudata;
+  if (u) {
+    do {
+      u = u->gch.next;
+      makewhite(g, u);  /* may be marked, if left from previous GC */
+      reallymarkobject(g, u);
+    } while (u != g->tmudata);
+  }
+}
+
+
+/* move `dead' udata that need finalization to list `tmudata' */
+size_t luaC_separateudata (lua_State *L, int all) {
+  global_State *g = G(L);
+  size_t deadmem = 0;
+  GCObject **p = &g->mainthread->next;
+  GCObject *curr;
+  while ((curr = *p) != NULL) {
+    if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
+      p = &curr->gch.next;  /* don't bother with them */
+    else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
+      markfinalized(gco2u(curr));  /* don't need finalization */
+      p = &curr->gch.next;
+    }
+    else {  /* must call its gc method */
+      deadmem += sizeudata(gco2u(curr));
+      markfinalized(gco2u(curr));
+      *p = curr->gch.next;
+      /* link `curr' at the end of `tmudata' list */
+      if (g->tmudata == NULL)  /* list is empty? */
+        g->tmudata = curr->gch.next = curr;  /* creates a circular list */
+      else {
+        curr->gch.next = g->tmudata->gch.next;
+        g->tmudata->gch.next = curr;
+        g->tmudata = curr;
+      }
+    }
+  }
+  return deadmem;
+}
+
+
+static int traversetable (global_State *g, Table *h) {
+  int i;
+  int weakkey = 0;
+  int weakvalue = 0;
+  const TValue *mode;
+  if (h->metatable)
+    markobject(g, h->metatable);
+  mode = gfasttm(g, h->metatable, TM_MODE);
+  if (mode && ttisstring(mode)) {  /* is there a weak mode? */
+    weakkey = (strchr(svalue(mode), 'k') != NULL);
+    weakvalue = (strchr(svalue(mode), 'v') != NULL);
+    if (weakkey || weakvalue) {  /* is really weak? */
+      h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
+      h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
+                             (weakvalue << VALUEWEAKBIT));
+      h->gclist = g->weak;  /* must be cleared after GC, ... */
+      g->weak = obj2gco(h);  /* ... so put in the appropriate list */
+    }
+  }
+  if (weakkey && weakvalue) return 1;
+  if (!weakvalue) {
+    i = h->sizearray;
+    while (i--)
+      markvalue(g, &h->array[i]);
+  }
+  i = sizenode(h);
+  while (i--) {
+    Node *n = gnode(h, i);
+    lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
+    if (ttisnil(gval(n)))
+      removeentry(n);  /* remove empty entries */
+    else {
+      lua_assert(!ttisnil(gkey(n)));
+      if (!weakkey) markvalue(g, gkey(n));
+      if (!weakvalue) markvalue(g, gval(n));
+    }
+  }
+  return weakkey || weakvalue;
+}
+
+
+/*
+** All marks are conditional because a GC may happen while the
+** prototype is still being created
+*/
+static void traverseproto (global_State *g, Proto *f) {
+  int i;
+  if (f->source) stringmark(f->source);
+  for (i=0; i<f->sizek; i++)  /* mark literals */
+    markvalue(g, &f->k[i]);
+  for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */
+    if (f->upvalues[i])
+      stringmark(f->upvalues[i]);
+  }
+  for (i=0; i<f->sizep; i++) {  /* mark nested protos */
+    if (f->p[i])
+      markobject(g, f->p[i]);
+  }
+  for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */
+    if (f->locvars[i].varname)
+      stringmark(f->locvars[i].varname);
+  }
+}
+
+
+
+static void traverseclosure (global_State *g, Closure *cl) {
+  markobject(g, cl->c.env);
+  if (cl->c.isC) {
+    int i;
+    for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */
+      markvalue(g, &cl->c.upvalue[i]);
+  }
+  else {
+    int i;
+    lua_assert(cl->l.nupvalues == cl->l.p->nups);
+    markobject(g, cl->l.p);
+    for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
+      markobject(g, cl->l.upvals[i]);
+  }
+}
+
+
+static void checkstacksizes (lua_State *L, StkId max) {
+  int ci_used = cast_int(L->ci - L->base_ci);  /* number of `ci' in use */
+  int s_used = cast_int(max - L->stack);  /* part of stack in use */
+  if (L->size_ci > LUAI_MAXCALLS)  /* handling overflow? */
+    return;  /* do not touch the stacks */
+  if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
+    luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */
+  condhardstacktests(luaD_reallocCI(L, ci_used + 1));
+  if (4*s_used < L->stacksize &&
+      2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
+    luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */
+  condhardstacktests(luaD_reallocstack(L, s_used));
+}
+
+
+static void traversestack (global_State *g, lua_State *l) {
+  StkId o, lim;
+  CallInfo *ci;
+  markvalue(g, gt(l));
+  lim = l->top;
+  for (ci = l->base_ci; ci <= l->ci; ci++) {
+    lua_assert(ci->top <= l->stack_last);
+    if (lim < ci->top) lim = ci->top;
+  }
+  for (o = l->stack; o < l->top; o++)
+    markvalue(g, o);
+  for (; o <= lim; o++)
+    setnilvalue(o);
+  checkstacksizes(l, lim);
+}
+
+
+/*
+** traverse one gray object, turning it to black.
+** Returns `quantity' traversed.
+*/
+static l_mem propagatemark (global_State *g) {
+  GCObject *o = g->gray;
+  lua_assert(isgray(o));
+  gray2black(o);
+  switch (o->gch.tt) {
+    case LUA_TTABLE: {
+      Table *h = gco2h(o);
+      g->gray = h->gclist;
+      if (traversetable(g, h))  /* table is weak? */
+        black2gray(o);  /* keep it gray */
+      return sizeof(Table) + sizeof(TValue) * h->sizearray +
+                             sizeof(Node) * sizenode(h);
+    }
+    case LUA_TFUNCTION: {
+      Closure *cl = gco2cl(o);
+      g->gray = cl->c.gclist;
+      traverseclosure(g, cl);
+      return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
+                           sizeLclosure(cl->l.nupvalues);
+    }
+    case LUA_TTHREAD: {
+      lua_State *th = gco2th(o);
+      g->gray = th->gclist;
+      th->gclist = g->grayagain;
+      g->grayagain = o;
+      black2gray(o);
+      traversestack(g, th);
+      return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+                                 sizeof(CallInfo) * th->size_ci;
+    }
+    case LUA_TPROTO: {
+      Proto *p = gco2p(o);
+      g->gray = p->gclist;
+      traverseproto(g, p);
+      return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
+                             sizeof(Proto *) * p->sizep +
+                             sizeof(TValue) * p->sizek + 
+                             sizeof(int) * p->sizelineinfo +
+                             sizeof(LocVar) * p->sizelocvars +
+                             sizeof(TString *) * p->sizeupvalues;
+    }
+    default: lua_assert(0); return 0;
+  }
+}
+
+
+static size_t propagateall (global_State *g) {
+  size_t m = 0;
+  while (g->gray) m += propagatemark(g);
+  return m;
+}
+
+
+/*
+** The next function tells whether a key or value can be cleared from
+** a weak table. Non-collectable objects are never removed from weak
+** tables. Strings behave as `values', so are never removed too. for
+** other objects: if really collected, cannot keep them; for userdata
+** being finalized, keep them in keys, but not in values
+*/
+static int iscleared (const TValue *o, int iskey) {
+  if (!iscollectable(o)) return 0;
+  if (ttisstring(o)) {
+    stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */
+    return 0;
+  }
+  return iswhite(gcvalue(o)) ||
+    (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
+}
+
+
+/*
+** clear collected entries from weaktables
+*/
+static void cleartable (GCObject *l) {
+  while (l) {
+    Table *h = gco2h(l);
+    int i = h->sizearray;
+    lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
+               testbit(h->marked, KEYWEAKBIT));
+    if (testbit(h->marked, VALUEWEAKBIT)) {
+      while (i--) {
+        TValue *o = &h->array[i];
+        if (iscleared(o, 0))  /* value was collected? */
+          setnilvalue(o);  /* remove value */
+      }
+    }
+    i = sizenode(h);
+    while (i--) {
+      Node *n = gnode(h, i);
+      if (!ttisnil(gval(n)) &&  /* non-empty entry? */
+          (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
+        setnilvalue(gval(n));  /* remove value ... */
+        removeentry(n);  /* remove entry from table */
+      }
+    }
+    l = h->gclist;
+  }
+}
+
+
+static void freeobj (lua_State *L, GCObject *o) {
+  switch (o->gch.tt) {
+    case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
+    case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
+    case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
+    case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
+    case LUA_TTHREAD: {
+      lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
+      luaE_freethread(L, gco2th(o));
+      break;
+    }
+    case LUA_TSTRING: {
+      G(L)->strt.nuse--;
+      luaM_freemem(L, o, sizestring(gco2ts(o)));
+      break;
+    }
+    case LUA_TUSERDATA: {
+      luaM_freemem(L, o, sizeudata(gco2u(o)));
+      break;
+    }
+    default: lua_assert(0);
+  }
+}
+
+
+
+#define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM)
+
+
+static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
+  GCObject *curr;
+  global_State *g = G(L);
+  int deadmask = otherwhite(g);
+  while ((curr = *p) != NULL && count-- > 0) {
+    if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */
+      sweepwholelist(L, &gco2th(curr)->openupval);
+    if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */
+      lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
+      makewhite(g, curr);  /* make it white (for next cycle) */
+      p = &curr->gch.next;
+    }
+    else {  /* must erase `curr' */
+      lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
+      *p = curr->gch.next;
+      if (curr == g->rootgc)  /* is the first element of the list? */
+        g->rootgc = curr->gch.next;  /* adjust first */
+      freeobj(L, curr);
+    }
+  }
+  return p;
+}
+
+
+static void checkSizes (lua_State *L) {
+  global_State *g = G(L);
+  /* check size of string hash */
+  if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
+      g->strt.size > MINSTRTABSIZE*2)
+    luaS_resize(L, g->strt.size/2);  /* table is too big */
+  /* check size of buffer */
+  if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
+    size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
+    luaZ_resizebuffer(L, &g->buff, newsize);
+  }
+}
+
+
+static void GCTM (lua_State *L) {
+  global_State *g = G(L);
+  GCObject *o = g->tmudata->gch.next;  /* get first element */
+  Udata *udata = rawgco2u(o);
+  const TValue *tm;
+  /* remove udata from `tmudata' */
+  if (o == g->tmudata)  /* last element? */
+    g->tmudata = NULL;
+  else
+    g->tmudata->gch.next = udata->uv.next;
+  udata->uv.next = g->mainthread->next;  /* return it to `root' list */
+  g->mainthread->next = o;
+  makewhite(g, o);
+  tm = fasttm(L, udata->uv.metatable, TM_GC);
+  if (tm != NULL) {
+    lu_byte oldah = L->allowhook;
+    lu_mem oldt = g->GCthreshold;
+    L->allowhook = 0;  /* stop debug hooks during GC tag method */
+    g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */
+    setobj2s(L, L->top, tm);
+    setuvalue(L, L->top+1, udata);
+    L->top += 2;
+    luaD_call(L, L->top - 2, 0);
+    L->allowhook = oldah;  /* restore hooks */
+    g->GCthreshold = oldt;  /* restore threshold */
+  }
+}
+
+
+/*
+** Call all GC tag methods
+*/
+void luaC_callGCTM (lua_State *L) {
+  while (G(L)->tmudata)
+    GCTM(L);
+}
+
+
+void luaC_freeall (lua_State *L) {
+  global_State *g = G(L);
+  int i;
+  g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);  /* mask to collect all elements */
+  sweepwholelist(L, &g->rootgc);
+  for (i = 0; i < g->strt.size; i++)  /* free all string lists */
+    sweepwholelist(L, &g->strt.hash[i]);
+}
+
+
+static void markmt (global_State *g) {
+  int i;
+  for (i=0; i<NUM_TAGS; i++)
+    if (g->mt[i]) markobject(g, g->mt[i]);
+}
+
+
+/* mark root set */
+static void markroot (lua_State *L) {
+  global_State *g = G(L);
+  g->gray = NULL;
+  g->grayagain = NULL;
+  g->weak = NULL;
+  markobject(g, g->mainthread);
+  /* make global table be traversed before main stack */
+  markvalue(g, gt(g->mainthread));
+  markvalue(g, registry(L));
+  markmt(g);
+  g->gcstate = GCSpropagate;
+}
+
+
+static void remarkupvals (global_State *g) {
+  UpVal *uv;
+  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
+    lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+    if (isgray(obj2gco(uv)))
+      markvalue(g, uv->v);
+  }
+}
+
+
+static void atomic (lua_State *L) {
+  global_State *g = G(L);
+  size_t udsize;  /* total size of userdata to be finalized */
+  /* remark occasional upvalues of (maybe) dead threads */
+  remarkupvals(g);
+  /* traverse objects cautch by write barrier and by 'remarkupvals' */
+  propagateall(g);
+  /* remark weak tables */
+  g->gray = g->weak;
+  g->weak = NULL;
+  lua_assert(!iswhite(obj2gco(g->mainthread)));
+  markobject(g, L);  /* mark running thread */
+  markmt(g);  /* mark basic metatables (again) */
+  propagateall(g);
+  /* remark gray again */
+  g->gray = g->grayagain;
+  g->grayagain = NULL;
+  propagateall(g);
+  udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */
+  marktmu(g);  /* mark `preserved' userdata */
+  udsize += propagateall(g);  /* remark, to propagate `preserveness' */
+  cleartable(g->weak);  /* remove collected objects from weak tables */
+  /* flip current white */
+  g->currentwhite = cast_byte(otherwhite(g));
+  g->sweepstrgc = 0;
+  g->sweepgc = &g->rootgc;
+  g->gcstate = GCSsweepstring;
+  g->estimate = g->totalbytes - udsize;  /* first estimate */
+}
+
+
+static l_mem singlestep (lua_State *L) {
+  global_State *g = G(L);
+  /*lua_checkmemory(L);*/
+  switch (g->gcstate) {
+    case GCSpause: {
+      markroot(L);  /* start a new collection */
+      return 0;
+    }
+    case GCSpropagate: {
+      if (g->gray)
+        return propagatemark(g);
+      else {  /* no more `gray' objects */
+        atomic(L);  /* finish mark phase */
+        return 0;
+      }
+    }
+    case GCSsweepstring: {
+      lu_mem old = g->totalbytes;
+      sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
+      if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
+        g->gcstate = GCSsweep;  /* end sweep-string phase */
+      lua_assert(old >= g->totalbytes);
+      g->estimate -= old - g->totalbytes;
+      return GCSWEEPCOST;
+    }
+    case GCSsweep: {
+      lu_mem old = g->totalbytes;
+      g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+      if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
+        checkSizes(L);
+        g->gcstate = GCSfinalize;  /* end sweep phase */
+      }
+      lua_assert(old >= g->totalbytes);
+      g->estimate -= old - g->totalbytes;
+      return GCSWEEPMAX*GCSWEEPCOST;
+    }
+    case GCSfinalize: {
+      if (g->tmudata) {
+        GCTM(L);
+        if (g->estimate > GCFINALIZECOST)
+          g->estimate -= GCFINALIZECOST;
+        return GCFINALIZECOST;
+      }
+      else {
+        g->gcstate = GCSpause;  /* end collection */
+        g->gcdept = 0;
+        return 0;
+      }
+    }
+    default: lua_assert(0); return 0;
+  }
+}
+
+
+void luaC_step (lua_State *L) {
+  global_State *g = G(L);
+  l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
+  if (lim == 0)
+    lim = (MAX_LUMEM-1)/2;  /* no limit */
+  g->gcdept += g->totalbytes - g->GCthreshold;
+  do {
+    lim -= singlestep(L);
+    if (g->gcstate == GCSpause)
+      break;
+  } while (lim > 0);
+  if (g->gcstate != GCSpause) {
+    if (g->gcdept < GCSTEPSIZE)
+      g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/g->gcstepmul;*/
+    else {
+      g->gcdept -= GCSTEPSIZE;
+      g->GCthreshold = g->totalbytes;
+    }
+  }
+  else {
+    lua_assert(g->totalbytes >= g->estimate);
+    setthreshold(g);
+  }
+}
+
+
+void luaC_fullgc (lua_State *L) {
+  global_State *g = G(L);
+  if (g->gcstate <= GCSpropagate) {
+    /* reset sweep marks to sweep all elements (returning them to white) */
+    g->sweepstrgc = 0;
+    g->sweepgc = &g->rootgc;
+    /* reset other collector lists */
+    g->gray = NULL;
+    g->grayagain = NULL;
+    g->weak = NULL;
+    g->gcstate = GCSsweepstring;
+  }
+  lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
+  /* finish any pending sweep phase */
+  while (g->gcstate != GCSfinalize) {
+    lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
+    singlestep(L);
+  }
+  markroot(L);
+  while (g->gcstate != GCSpause) {
+    singlestep(L);
+  }
+  setthreshold(g);
+}
+
+
+void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
+  global_State *g = G(L);
+  lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
+  lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+  lua_assert(ttype(&o->gch) != LUA_TTABLE);
+  /* must keep invariant? */
+  if (g->gcstate == GCSpropagate)
+    reallymarkobject(g, v);  /* restore invariant */
+  else  /* don't mind */
+    makewhite(g, o);  /* mark as white just to avoid other barriers */
+}
+
+
+void luaC_barrierback (lua_State *L, Table *t) {
+  global_State *g = G(L);
+  GCObject *o = obj2gco(t);
+  lua_assert(isblack(o) && !isdead(g, o));
+  lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+  black2gray(o);  /* make table gray (again) */
+  t->gclist = g->grayagain;
+  g->grayagain = o;
+}
+
+
+void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
+  global_State *g = G(L);
+  o->gch.next = g->rootgc;
+  g->rootgc = o;
+  o->gch.marked = luaC_white(g);
+  o->gch.tt = tt;
+}
+
+
+void luaC_linkupval (lua_State *L, UpVal *uv) {
+  global_State *g = G(L);
+  GCObject *o = obj2gco(uv);
+  o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */
+  g->rootgc = o;
+  if (isgray(o)) { 
+    if (g->gcstate == GCSpropagate) {
+      gray2black(o);  /* closed upvalues need barrier */
+      luaC_barrier(L, uv, uv->v);
+    }
+    else {  /* sweep phase: sweep it (turning it into white) */
+      makewhite(g, o);
+      lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
+    }
+  }
+}
+

=== added file 'lua/lgc.h'
--- lua/lgc.h	1970-01-01 00:00:00 +0000
+++ lua/lgc.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,110 @@
+/*
+** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $
+** Garbage Collector
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lgc_h
+#define lgc_h
+
+
+#include "lobject.h"
+
+
+/*
+** Possible states of the Garbage Collector
+*/
+#define GCSpause	0
+#define GCSpropagate	1
+#define GCSsweepstring	2
+#define GCSsweep	3
+#define GCSfinalize	4
+
+
+/*
+** some userful bit tricks
+*/
+#define resetbits(x,m)	((x) &= cast(lu_byte, ~(m)))
+#define setbits(x,m)	((x) |= (m))
+#define testbits(x,m)	((x) & (m))
+#define bitmask(b)	(1<<(b))
+#define bit2mask(b1,b2)	(bitmask(b1) | bitmask(b2))
+#define l_setbit(x,b)	setbits(x, bitmask(b))
+#define resetbit(x,b)	resetbits(x, bitmask(b))
+#define testbit(x,b)	testbits(x, bitmask(b))
+#define set2bits(x,b1,b2)	setbits(x, (bit2mask(b1, b2)))
+#define reset2bits(x,b1,b2)	resetbits(x, (bit2mask(b1, b2)))
+#define test2bits(x,b1,b2)	testbits(x, (bit2mask(b1, b2)))
+
+
+
+/*
+** Layout for bit use in `marked' field:
+** bit 0 - object is white (type 0)
+** bit 1 - object is white (type 1)
+** bit 2 - object is black
+** bit 3 - for userdata: has been finalized
+** bit 3 - for tables: has weak keys
+** bit 4 - for tables: has weak values
+** bit 5 - object is fixed (should not be collected)
+** bit 6 - object is "super" fixed (only the main thread)
+*/
+
+
+#define WHITE0BIT	0
+#define WHITE1BIT	1
+#define BLACKBIT	2
+#define FINALIZEDBIT	3
+#define KEYWEAKBIT	3
+#define VALUEWEAKBIT	4
+#define FIXEDBIT	5
+#define SFIXEDBIT	6
+#define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
+
+
+#define iswhite(x)      test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
+#define isblack(x)      testbit((x)->gch.marked, BLACKBIT)
+#define isgray(x)	(!isblack(x) && !iswhite(x))
+
+#define otherwhite(g)	(g->currentwhite ^ WHITEBITS)
+#define isdead(g,v)	((v)->gch.marked & otherwhite(g) & WHITEBITS)
+
+#define changewhite(x)	((x)->gch.marked ^= WHITEBITS)
+#define gray2black(x)	l_setbit((x)->gch.marked, BLACKBIT)
+
+#define valiswhite(x)	(iscollectable(x) && iswhite(gcvalue(x)))
+
+#define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
+
+
+#define luaC_checkGC(L) { \
+  condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \
+  if (G(L)->totalbytes >= G(L)->GCthreshold) \
+	luaC_step(L); }
+
+
+#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \
+	luaC_barrierf(L,obj2gco(p),gcvalue(v)); }
+
+#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t)))  \
+	luaC_barrierback(L,t); }
+
+#define luaC_objbarrier(L,p,o)  \
+	{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
+		luaC_barrierf(L,obj2gco(p),obj2gco(o)); }
+
+#define luaC_objbarriert(L,t,o)  \
+   { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); }
+
+LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all);
+LUAI_FUNC void luaC_callGCTM (lua_State *L);
+LUAI_FUNC void luaC_freeall (lua_State *L);
+LUAI_FUNC void luaC_step (lua_State *L);
+LUAI_FUNC void luaC_fullgc (lua_State *L);
+LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
+LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
+LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
+LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
+
+
+#endif

=== added file 'lua/linit.c'
--- lua/linit.c	1970-01-01 00:00:00 +0000
+++ lua/linit.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,46 @@
+/*
+** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $
+** Initialization of libraries for lua.c
+** See Copyright Notice in lua.h
+*/
+
+
+#define linit_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lualib.h"
+#include "lauxlib.h"
+
+
+static const luaL_Reg lualibs[] = {
+  {"", luaopen_base},
+#ifndef USE_GRUB_LIB
+  {LUA_LOADLIBNAME, luaopen_package},
+#endif /* ! USE_GRUB_LIB */
+  {LUA_TABLIBNAME, luaopen_table},
+#ifndef USE_GRUB_LIB
+  {LUA_IOLIBNAME, luaopen_io},
+#endif /* ! USE_GRUB_LIB */
+#ifndef USE_GRUB_LIB
+  {LUA_OSLIBNAME, luaopen_os},
+#endif /* ! USE_GRUB_LIB */
+  {LUA_STRLIBNAME, luaopen_string},
+#if !defined LUA_NUMBER_INTEGRAL
+  {LUA_MATHLIBNAME, luaopen_math},
+#endif
+  {LUA_DBLIBNAME, luaopen_debug},
+  {NULL, NULL}
+};
+
+
+LUALIB_API void luaL_openlibs (lua_State *L) {
+  const luaL_Reg *lib = lualibs;
+  for (; lib->func; lib++) {
+    lua_pushcfunction(L, lib->func);
+    lua_pushstring(L, lib->name);
+    lua_call(L, 1, 0);
+  }
+}
+

=== added file 'lua/liolib.c'
--- lua/liolib.c	1970-01-01 00:00:00 +0000
+++ lua/liolib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,578 @@
+/*
+** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $
+** Standard I/O (and system) library
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define liolib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+#define IO_INPUT	1
+#define IO_OUTPUT	2
+
+
+static const char *const fnames[] = {"input", "output"};
+
+
+static int pushresult (lua_State *L, int i, const char *filename) {
+  if (i) {
+    lua_pushboolean(L, 1);
+    return 1;
+  }
+  else {
+    lua_pushnil(L);
+    if (filename)
+      lua_pushfstring(L, "%s: %s", filename, grub_errmsg);
+    else
+      lua_pushfstring(L, "%s", grub_errmsg);
+    lua_pushinteger(L, grub_errno);
+    return 3;
+  }
+}
+
+
+static void fileerror (lua_State *L, int arg, const char *filename) {
+  lua_pushfstring(L, "%s: %s", filename, grub_errmsg);
+  luaL_argerror(L, arg, lua_tostring(L, -1));
+}
+
+
+#define tofilep(L)	((grub_file_t *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
+
+
+static int io_type (lua_State *L) {
+  void *ud;
+  luaL_checkany(L, 1);
+  ud = lua_touserdata(L, 1);
+  lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE);
+  if (ud == NULL || !lua_getmetatable(L, 1) || !lua_rawequal(L, -2, -1))
+    lua_pushnil(L);  /* not a file */
+  else if (*((grub_file_t *)ud) == NULL)
+    lua_pushliteral(L, "closed file");
+  else
+    lua_pushliteral(L, "file");
+  return 1;
+}
+
+
+static grub_file_t tofile (lua_State *L) {
+  grub_file_t *f = tofilep(L);
+  if (*f == NULL)
+    luaL_error(L, "attempt to use a closed file");
+  return *f;
+}
+
+
+
+/*
+** When creating file handles, always creates a `closed' file handle
+** before opening the actual file; so, if there is a memory error, the
+** file is not left opened.
+*/
+static grub_file_t *newfile (lua_State *L) {
+  grub_file_t *pf = (grub_file_t *)lua_newuserdata(L, sizeof(grub_file_t));
+  *pf = NULL;  /* file handle is currently `closed' */
+  luaL_getmetatable(L, LUA_FILEHANDLE);
+  lua_setmetatable(L, -2);
+  return pf;
+}
+
+
+/*
+** function to (not) close the standard files stdin, stdout, and stderr
+*/
+static int io_noclose (lua_State *L) {
+  lua_pushnil(L);
+  lua_pushliteral(L, "cannot close standard file");
+  return 2;
+}
+
+
+/*
+** function to close regular files
+*/
+static int io_fclose (lua_State *L) {
+  grub_file_t *p = tofilep(L);
+  int ok = (grub_file_close(*p) == 0);
+  *p = NULL;
+  return pushresult(L, ok, NULL);
+}
+
+
+static int aux_close (lua_State *L) {
+  lua_getfenv(L, 1);
+  lua_getfield(L, -1, "__close");
+  return (lua_tocfunction(L, -1))(L);
+}
+
+
+static int io_close (lua_State *L) {
+  if (lua_isnone(L, 1))
+    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT);
+  tofile(L);  /* make sure argument is a file */
+  return aux_close(L);
+}
+
+
+static int io_gc (lua_State *L) {
+  grub_file_t f = *tofilep(L);
+  /* ignore closed files */
+  if (f != NULL)
+    aux_close(L);
+  return 0;
+}
+
+
+static int io_tostring (lua_State *L) {
+  grub_file_t f = *tofilep(L);
+  if (f == NULL)
+    lua_pushliteral(L, "file (closed)");
+  else
+    lua_pushfstring(L, "file (%p)", f);
+  return 1;
+}
+
+
+static int io_open (lua_State *L) {
+  const char *filename = luaL_checkstring(L, 1);
+  const char *mode = luaL_optstring(L, 2, "r");
+  grub_file_t *pf = newfile(L);
+  UNUSED(mode);
+  *pf = grub_buffile_open(filename, 0);
+  return (*pf == NULL) ? pushresult(L, 0, filename) : 1;
+}
+
+
+static grub_file_t getiofile (lua_State *L, int findex) {
+  grub_file_t f;
+  lua_rawgeti(L, LUA_ENVIRONINDEX, findex);
+  f = *(grub_file_t *)lua_touserdata(L, -1);
+  if (f == NULL)
+    luaL_error(L, "standard %s file is closed", fnames[findex - 1]);
+  return f;
+}
+
+
+static int g_iofile (lua_State *L, int f, const char *mode) {
+  if (!lua_isnoneornil(L, 1)) {
+    const char *filename = lua_tostring(L, 1);
+    if (filename) {
+      grub_file_t *pf = newfile(L);
+      *pf = grub_buffile_open(filename, 0);
+      if (*pf == NULL)
+        fileerror(L, 1, filename);
+    }
+    else {
+      tofile(L);  /* check that it's a valid file handle */
+      lua_pushvalue(L, 1);
+    }
+    lua_rawseti(L, LUA_ENVIRONINDEX, f);
+  }
+  /* return current value */
+  lua_rawgeti(L, LUA_ENVIRONINDEX, f);
+  return 1;
+}
+
+
+static int io_input (lua_State *L) {
+  return g_iofile(L, IO_INPUT, "r");
+}
+
+
+static int io_output (lua_State *L) {
+  return g_iofile(L, IO_OUTPUT, "w");
+}
+
+
+static int io_readline (lua_State *L);
+
+
+static void aux_lines (lua_State *L, int idx, int toclose) {
+  lua_pushvalue(L, idx);
+  lua_pushboolean(L, toclose);  /* close/not close file when finished */
+  lua_pushcclosure(L, io_readline, 2);
+}
+
+
+static int f_lines (lua_State *L) {
+  tofile(L);  /* check that it's a valid file handle */
+  aux_lines(L, 1, 0);
+  return 1;
+}
+
+
+static int io_lines (lua_State *L) {
+  if (lua_isnoneornil(L, 1)) {  /* no arguments? */
+    /* will iterate over default input */
+    lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT);
+    return f_lines(L);
+  }
+  else {
+    const char *filename = luaL_checkstring(L, 1);
+    grub_file_t *pf = newfile(L);
+    *pf = grub_buffile_open(filename, 0);
+    if (*pf == NULL)
+      fileerror(L, 1, filename);
+    aux_lines(L, lua_gettop(L), 1);
+    return 1;
+  }
+}
+
+
+/*
+** {======================================================
+** READ
+** =======================================================
+*/
+
+
+static int read_number (lua_State *L, grub_file_t f) {
+  lua_Number d;
+  char buf[32];
+  char *endptr;
+  int len;
+  int found_digit;
+  len = 0;
+  found_digit = 0;
+  while (len < sizeof(buf) - 1)
+    {
+      if (grub_file_read (f, &buf[len], 1) != 1)
+        break;
+
+      if (found_digit)
+        {
+          if (! isdigit (buf[len]))
+            break;
+        }
+      else
+        {
+          if (isdigit (buf[len]))
+            found_digit = 1;
+        }
+     
+      len++;
+    }
+  buf[len] = '\0';
+  d = strtol (buf, &endptr, 10);
+  if (buf[0] != '\0' && endptr > &buf[0]) {
+    lua_pushnumber(L, d);
+    return 1;
+  }
+  else return 0;  /* read fails */
+}
+
+
+static int test_eof (lua_State *L, grub_file_t f) {
+  lua_pushlstring(L, NULL, 0);
+  return (grub_file_tell (f) < grub_file_size (f));
+}
+
+
+static int read_line (lua_State *L, grub_file_t f) {
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  for (;;) {
+    size_t l;
+    char *p = luaL_prepbuffer(&b);
+    if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) {  /* eof? */
+      luaL_pushresult(&b);  /* close buffer */
+      return (lua_objlen(L, -1) > 0);  /* check whether read something */
+    }
+    l = strlen(p);
+    if (l == 0 || p[l-1] != '\n')
+      luaL_addsize(&b, l);
+    else {
+      luaL_addsize(&b, l - 1);  /* do not include `eol' */
+      luaL_pushresult(&b);  /* close buffer */
+      return 1;  /* read at least an `eol' */
+    }
+  }
+}
+
+
+static int read_chars (lua_State *L, grub_file_t f, size_t n) {
+  size_t rlen;  /* how much to read */
+  size_t nr;  /* number of chars actually read */
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
+  do {
+    ssize_t ret;
+    char *p = luaL_prepbuffer(&b);
+    if (rlen > n) rlen = n;  /* cannot read more than asked */
+    ret = grub_file_read (f, p, rlen);
+    if (ret == -1)
+      break;
+    nr = (size_t) ret;
+    luaL_addsize(&b, nr);
+    n -= nr;  /* still have to read `n' chars */
+  } while (n > 0 && nr == rlen);  /* until end of count or eof */
+  luaL_pushresult(&b);  /* close buffer */
+  return (n == 0 || lua_objlen(L, -1) > 0);
+}
+
+
+static int g_read (lua_State *L, grub_file_t f, int first) {
+  int nargs = lua_gettop(L) - 1;
+  int success;
+  int n;
+  grub_errno = GRUB_ERR_NONE;
+  if (nargs == 0) {  /* no arguments? */
+    success = read_line(L, f);
+    n = first+1;  /* to return 1 result */
+  }
+  else {  /* ensure stack space for all results and for auxlib's buffer */
+    luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
+    success = 1;
+    for (n = first; nargs-- && success; n++) {
+      if (lua_type(L, n) == LUA_TNUMBER) {
+        size_t l = (size_t)lua_tointeger(L, n);
+        success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
+      }
+      else {
+        const char *p = lua_tostring(L, n);
+        luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
+        switch (p[1]) {
+          case 'n':  /* number */
+            success = read_number(L, f);
+            break;
+          case 'l':  /* line */
+            success = read_line(L, f);
+            break;
+          case 'a':  /* file */
+            read_chars(L, f, ~((size_t)0));  /* read MAX_SIZE_T chars */
+            success = 1; /* always success */
+            break;
+          default:
+            return luaL_argerror(L, n, "invalid format");
+        }
+      }
+    }
+  }
+  if (grub_errno != GRUB_ERR_NONE)
+    return pushresult(L, 0, NULL);
+  if (!success) {
+    lua_pop(L, 1);  /* remove last result */
+    lua_pushnil(L);  /* push nil instead */
+  }
+  return n - first;
+}
+
+
+static int io_read (lua_State *L) {
+  return g_read(L, getiofile(L, IO_INPUT), 1);
+}
+
+
+static int f_read (lua_State *L) {
+  return g_read(L, tofile(L), 2);
+}
+
+
+static int io_readline (lua_State *L) {
+  grub_file_t f = *(grub_file_t *)lua_touserdata(L, lua_upvalueindex(1));
+  int sucess;
+  if (f == NULL)  /* file is already closed? */
+    luaL_error(L, "file is already closed");
+  grub_errno = GRUB_ERR_NONE;
+  sucess = read_line(L, f);
+  if (grub_errno != GRUB_ERR_NONE)
+    return luaL_error(L, "%s", grub_errmsg);
+  if (sucess) return 1;
+  else {  /* EOF */
+    if (lua_toboolean(L, lua_upvalueindex(2))) {  /* generator created file? */
+      lua_settop(L, 0);
+      lua_pushvalue(L, lua_upvalueindex(1));
+      aux_close(L);  /* close it */
+    }
+    return 0;
+  }
+}
+
+/* }====================================================== */
+
+
+static int g_write (lua_State *L, grub_file_t f, int arg) {
+  int nargs = lua_gettop(L) - 1;
+  int status = 1;
+  for (; nargs--; arg++) {
+    if (lua_type(L, arg) == LUA_TNUMBER) {
+      /* optimization: could be done exactly as for strings */
+      if (status)
+        {
+          char buf[32];
+          size_t n;
+          grub_sprintf (buf, LUA_NUMBER_FMT, lua_tonumber (L, arg));
+          n = strlen (buf);
+          status = (grub_file_write (f, buf, n) == n);
+        }
+    }
+    else {
+      size_t l;
+      const char *s = luaL_checklstring(L, arg, &l);
+      status = status && (grub_file_write(f, s, l) == l);
+    }
+  }
+  return pushresult(L, status, NULL);
+}
+
+
+static int io_write (lua_State *L) {
+  return g_write(L, getiofile(L, IO_OUTPUT), 1);
+}
+
+
+static int f_write (lua_State *L) {
+  return g_write(L, tofile(L), 2);
+}
+
+enum { 
+  SEEK_SET, SEEK_CUR, SEEK_END
+};
+
+static int do_grub_seek (grub_file_t f, long offset, int whence)
+{
+  grub_off_t pos;
+  switch (whence)
+    {
+    default:
+    case SEEK_SET:
+      pos = offset;
+      break;
+    case SEEK_CUR:
+      pos = ((long) grub_file_tell (f)) + offset;
+      break;
+    case SEEK_END:
+      pos = ((long) grub_file_size (f)) + offset;
+      break;
+    }
+  return grub_file_seek (f, pos);
+}
+
+static int f_seek (lua_State *L) {
+  static const char *const modenames[] = {"set", "cur", "end", NULL};
+  grub_file_t f = tofile(L);
+  int op = luaL_checkoption(L, 2, "cur", modenames);
+  long offset = luaL_optlong(L, 3, 0);
+  op = do_grub_seek (f, offset, mode[op]);
+  if (op)
+    return pushresult(L, 0, NULL);  /* error */
+  else {
+    lua_pushinteger(L, grub_file_tell (f));
+    return 1;
+  }
+}
+
+
+static int f_setvbuf (lua_State *L) {
+  /* For GRUB we simply report success.  */
+  lua_pushboolean (L, 1);
+  return 1;
+}
+
+
+
+static int io_flush (lua_State *L) {
+  /* For GRUB we simply report success.  */
+  lua_pushboolean (L, 1);
+  return 1;
+}
+
+
+static int f_flush (lua_State *L) {
+  /* For GRUB we simply report success.  */
+  lua_pushboolean (L, 1);
+  return 1;
+}
+
+
+static const luaL_Reg iolib[] = {
+  {"close", io_close},
+  {"flush", io_flush},
+  {"input", io_input},
+  {"lines", io_lines},
+  {"open", io_open},
+  {"output", io_output},
+  {"read", io_read},
+  {"type", io_type},
+  {"write", io_write},
+  {NULL, NULL}
+};
+
+
+static const luaL_Reg flib[] = {
+  {"close", io_close},
+  {"flush", f_flush},
+  {"lines", f_lines},
+  {"read", f_read},
+  {"seek", f_seek},
+  {"setvbuf", f_setvbuf},
+  {"write", f_write},
+  {"__gc", io_gc},
+  {"__tostring", io_tostring},
+  {NULL, NULL}
+};
+
+
+static void createmeta (lua_State *L) {
+  luaL_newmetatable(L, LUA_FILEHANDLE);  /* create metatable for file handles */
+  lua_pushvalue(L, -1);  /* push metatable */
+  lua_setfield(L, -2, "__index");  /* metatable.__index = metatable */
+  luaL_register(L, NULL, flib);  /* file methods */
+}
+
+
+static void createstdfile (lua_State *L, grub_file_t f, int k, const char *fname) {
+  *newfile(L) = f;
+  if (k > 0) {
+    lua_pushvalue(L, -1);
+    lua_rawseti(L, LUA_ENVIRONINDEX, k);
+  }
+  lua_pushvalue(L, -2);  /* copy environment */
+  lua_setfenv(L, -2);  /* set it */
+  lua_setfield(L, -3, fname);
+}
+
+
+static void newfenv (lua_State *L, lua_CFunction cls) {
+  lua_createtable(L, 0, 1);
+  lua_pushcfunction(L, cls);
+  lua_setfield(L, -2, "__close");
+}
+
+
+LUALIB_API int luaopen_io (lua_State *L) {
+  createmeta(L);
+  /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */
+  newfenv(L, io_fclose);
+  lua_replace(L, LUA_ENVIRONINDEX);
+  /* open library */
+  luaL_register(L, LUA_IOLIBNAME, iolib);
+  /* create (and set) default files */
+  newfenv(L, io_noclose);  /* close function for default files */
+  createstdfile(L, stdin, IO_INPUT, "stdin");
+  createstdfile(L, stdout, IO_OUTPUT, "stdout");
+  createstdfile(L, stderr, 0, "stderr");
+  lua_pop(L, 1);  /* pop environment for default files */
+  lua_getfield(L, -1, "popen");
+  newfenv(L, io_pclose);  /* create environment for 'popen' */
+  lua_setfenv(L, -2);  /* set fenv for 'popen' */
+  lua_pop(L, 1);  /* pop 'popen' */
+  return 1;
+}
+

=== added file 'lua/llex.c'
--- lua/llex.c	1970-01-01 00:00:00 +0000
+++ lua/llex.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,469 @@
+/*
+** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <ctype.h>
+#include <locale.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define llex_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "llex.h"
+#include "lobject.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lzio.h"
+
+
+
+#define next(ls) (ls->current = zgetc(ls->z))
+
+
+
+
+#define currIsNewline(ls)	(ls->current == '\n' || ls->current == '\r')
+
+
+/* ORDER RESERVED */
+const char *const luaX_tokens [] = {
+    "and", "break", "do", "else", "elseif",
+    "end", "false", "for", "function", "if",
+    "in", "local", "nil", "not", "or", "repeat",
+    "return", "then", "true", "until", "while",
+    "..", "...", "==", ">=", "<=", "~=",
+    "<number>", "<name>", "<string>", "<eof>",
+    NULL
+};
+
+
+#define save_and_next(ls) (save(ls, ls->current), next(ls))
+
+
+static void save (LexState *ls, int c) {
+  Mbuffer *b = ls->buff;
+  if (b->n + 1 > b->buffsize) {
+    size_t newsize;
+    if (b->buffsize >= MAX_SIZET/2)
+      luaX_lexerror(ls, "lexical element too long", 0);
+    newsize = b->buffsize * 2;
+    luaZ_resizebuffer(ls->L, b, newsize);
+  }
+  b->buffer[b->n++] = cast(char, c);
+}
+
+
+void luaX_init (lua_State *L) {
+  int i;
+  for (i=0; i<NUM_RESERVED; i++) {
+    TString *ts = luaS_new(L, luaX_tokens[i]);
+    luaS_fix(ts);  /* reserved words are never collected */
+    lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN);
+    ts->tsv.reserved = cast_byte(i+1);  /* reserved word */
+  }
+}
+
+
+#define MAXSRC          80
+
+
+const char *luaX_token2str (LexState *ls, int token) {
+  if (token < FIRST_RESERVED) {
+    lua_assert(token == cast(unsigned char, token));
+    return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) :
+                              luaO_pushfstring(ls->L, "%c", token);
+  }
+  else
+    return luaX_tokens[token-FIRST_RESERVED];
+}
+
+
+static const char *txtToken (LexState *ls, int token) {
+  switch (token) {
+    case TK_NAME:
+    case TK_STRING:
+    case TK_NUMBER:
+      save(ls, '\0');
+      return luaZ_buffer(ls->buff);
+    default:
+      return luaX_token2str(ls, token);
+  }
+}
+
+
+void luaX_lexerror (LexState *ls, const char *msg, int token) {
+  char buff[MAXSRC];
+  luaO_chunkid(buff, getstr(ls->source), MAXSRC);
+  msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
+  if (token)
+    luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token));
+  luaD_throw(ls->L, LUA_ERRSYNTAX);
+}
+
+
+void luaX_syntaxerror (LexState *ls, const char *msg) {
+  luaX_lexerror(ls, msg, ls->t.token);
+}
+
+
+TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
+  lua_State *L = ls->L;
+  TString *ts = luaS_newlstr(L, str, l);
+  TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */
+  if (ttisnil(o))
+    setbvalue(o, 1);  /* make sure `str' will not be collected */
+  return ts;
+}
+
+
+static void inclinenumber (LexState *ls) {
+  int old = ls->current;
+  lua_assert(currIsNewline(ls));
+  next(ls);  /* skip `\n' or `\r' */
+  if (currIsNewline(ls) && ls->current != old)
+    next(ls);  /* skip `\n\r' or `\r\n' */
+  if (++ls->linenumber >= MAX_INT)
+    luaX_syntaxerror(ls, "chunk has too many lines");
+}
+
+
+void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) {
+  ls->decpoint = '.';
+  ls->L = L;
+  ls->lookahead.token = TK_EOS;  /* no look-ahead token */
+  ls->z = z;
+  ls->fs = NULL;
+  ls->linenumber = 1;
+  ls->lastline = 1;
+  ls->source = source;
+  luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER);  /* initialize buffer */
+  next(ls);  /* read first char */
+}
+
+
+
+/*
+** =======================================================
+** LEXICAL ANALYZER
+** =======================================================
+*/
+
+
+
+static int check_next (LexState *ls, const char *set) {
+  if (!strchr(set, ls->current))
+    return 0;
+  save_and_next(ls);
+  return 1;
+}
+
+
+static void buffreplace (LexState *ls, char from, char to) {
+  size_t n = luaZ_bufflen(ls->buff);
+  char *p = luaZ_buffer(ls->buff);
+  while (n--)
+    if (p[n] == from) p[n] = to;
+}
+
+
+static void trydecpoint (LexState *ls, SemInfo *seminfo) {
+  /* format error: try to update decimal point separator */
+  char old = ls->decpoint;
+
+#ifdef USE_GRUB_LIB
+  ls->decpoint = '.';
+#else /* ! USE_GRUB_LIB */
+  struct lconv *cv = localeconv();
+  ls->decpoint = (cv ? cv->decimal_point[0] : '.');
+#endif /* ! USE_GRUB_LIB */
+
+  buffreplace(ls, old, ls->decpoint);  /* try updated decimal separator */
+  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) {
+    /* format error with correct decimal point: no more options */
+    buffreplace(ls, ls->decpoint, '.');  /* undo change (for error message) */
+    luaX_lexerror(ls, "malformed number", TK_NUMBER);
+  }
+}
+
+
+/* LUA_NUMBER */
+static void read_numeral (LexState *ls, SemInfo *seminfo) {
+  lua_assert(isdigit(ls->current));
+  do {
+    save_and_next(ls);
+  } while (isdigit(ls->current) || ls->current == '.');
+  if (check_next(ls, "Ee"))  /* `E'? */
+    check_next(ls, "+-");  /* optional exponent sign */
+  while (isalnum(ls->current) || ls->current == '_')
+    save_and_next(ls);
+  save(ls, '\0');
+  buffreplace(ls, '.', ls->decpoint);  /* follow locale for decimal point */
+  if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r))  /* format error? */
+    trydecpoint(ls, seminfo); /* try to update decimal point separator */
+}
+
+
+static int skip_sep (LexState *ls) {
+  int count = 0;
+  int s = ls->current;
+  lua_assert(s == '[' || s == ']');
+  save_and_next(ls);
+  while (ls->current == '=') {
+    save_and_next(ls);
+    count++;
+  }
+  return (ls->current == s) ? count : (-count) - 1;
+}
+
+
+static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
+  int cont = 0;
+  (void)(cont);  /* avoid warnings when `cont' is not used */
+  save_and_next(ls);  /* skip 2nd `[' */
+  if (currIsNewline(ls))  /* string starts with a newline? */
+    inclinenumber(ls);  /* skip it */
+  for (;;) {
+    switch (ls->current) {
+      case EOZ:
+        luaX_lexerror(ls, (seminfo) ? "unfinished long string" :
+                                   "unfinished long comment", TK_EOS);
+        break;  /* to avoid warnings */
+#if defined(LUA_COMPAT_LSTR)
+      case '[': {
+        if (skip_sep(ls) == sep) {
+          save_and_next(ls);  /* skip 2nd `[' */
+          cont++;
+#if LUA_COMPAT_LSTR == 1
+          if (sep == 0)
+            luaX_lexerror(ls, "nesting of [[...]] is deprecated", '[');
+#endif
+        }
+        break;
+      }
+#endif
+      case ']': {
+        if (skip_sep(ls) == sep) {
+          save_and_next(ls);  /* skip 2nd `]' */
+#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2
+          cont--;
+          if (sep == 0 && cont >= 0) break;
+#endif
+          goto endloop;
+        }
+        break;
+      }
+      case '\n':
+      case '\r': {
+        save(ls, '\n');
+        inclinenumber(ls);
+        if (!seminfo) luaZ_resetbuffer(ls->buff);  /* avoid wasting space */
+        break;
+      }
+      default: {
+        if (seminfo) save_and_next(ls);
+        else next(ls);
+      }
+    }
+  } endloop:
+  if (seminfo)
+    seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
+                                     luaZ_bufflen(ls->buff) - 2*(2 + sep));
+}
+
+
+static void read_string (LexState *ls, int del, SemInfo *seminfo) {
+  save_and_next(ls);
+  while (ls->current != del) {
+    switch (ls->current) {
+      case EOZ:
+        luaX_lexerror(ls, "unfinished string", TK_EOS);
+        continue;  /* to avoid warnings */
+      case '\n':
+      case '\r':
+        luaX_lexerror(ls, "unfinished string", TK_STRING);
+        continue;  /* to avoid warnings */
+      case '\\': {
+        int c;
+        next(ls);  /* do not save the `\' */
+        switch (ls->current) {
+          case 'a': c = '\a'; break;
+          case 'b': c = '\b'; break;
+          case 'f': c = '\f'; break;
+          case 'n': c = '\n'; break;
+          case 'r': c = '\r'; break;
+          case 't': c = '\t'; break;
+          case 'v': c = '\v'; break;
+          case '\n':  /* go through */
+          case '\r': save(ls, '\n'); inclinenumber(ls); continue;
+          case EOZ: continue;  /* will raise an error next loop */
+          default: {
+            if (!isdigit(ls->current))
+              save_and_next(ls);  /* handles \\, \", \', and \? */
+            else {  /* \xxx */
+              int i = 0;
+              c = 0;
+              do {
+                c = 10*c + (ls->current-'0');
+                next(ls);
+              } while (++i<3 && isdigit(ls->current));
+              if (c > UCHAR_MAX)
+                luaX_lexerror(ls, "escape sequence too large", TK_STRING);
+              save(ls, c);
+            }
+            continue;
+          }
+        }
+        save(ls, c);
+        next(ls);
+        continue;
+      }
+      default:
+        save_and_next(ls);
+    }
+  }
+  save_and_next(ls);  /* skip delimiter */
+  seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
+                                   luaZ_bufflen(ls->buff) - 2);
+}
+
+
+static int llex (LexState *ls, SemInfo *seminfo) {
+  luaZ_resetbuffer(ls->buff);
+  for (;;) {
+    switch (ls->current) {
+      case '\n':
+      case '\r': {
+        inclinenumber(ls);
+        continue;
+      }
+      case '-': {
+        next(ls);
+        if (ls->current != '-') return '-';
+        /* else is a comment */
+        next(ls);
+        if (ls->current == '[') {
+          int sep = skip_sep(ls);
+          luaZ_resetbuffer(ls->buff);  /* `skip_sep' may dirty the buffer */
+          if (sep >= 0) {
+            read_long_string(ls, NULL, sep);  /* long comment */
+            luaZ_resetbuffer(ls->buff);
+            continue;
+          }
+        }
+        /* else short comment */
+        while (!currIsNewline(ls) && ls->current != EOZ)
+          next(ls);
+        continue;
+      }
+      case '[': {
+        int sep = skip_sep(ls);
+        if (sep >= 0) {
+          read_long_string(ls, seminfo, sep);
+          return TK_STRING;
+        }
+        else if (sep == -1) return '[';
+        else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING);
+      }
+      case '=': {
+        next(ls);
+        if (ls->current != '=') return '=';
+        else { next(ls); return TK_EQ; }
+      }
+      case '<': {
+        next(ls);
+        if (ls->current != '=') return '<';
+        else { next(ls); return TK_LE; }
+      }
+      case '>': {
+        next(ls);
+        if (ls->current != '=') return '>';
+        else { next(ls); return TK_GE; }
+      }
+      case '~': {
+        next(ls);
+        if (ls->current != '=') return '~';
+        else { next(ls); return TK_NE; }
+      }
+      case '"':
+      case '\'': {
+        read_string(ls, ls->current, seminfo);
+        return TK_STRING;
+      }
+      case '.': {
+        save_and_next(ls);
+        if (check_next(ls, ".")) {
+          if (check_next(ls, "."))
+            return TK_DOTS;   /* ... */
+          else return TK_CONCAT;   /* .. */
+        }
+        else if (!isdigit(ls->current)) return '.';
+        else {
+          read_numeral(ls, seminfo);
+          return TK_NUMBER;
+        }
+      }
+      case EOZ: {
+        return TK_EOS;
+      }
+      default: {
+        if (isspace(ls->current)) {
+          lua_assert(!currIsNewline(ls));
+          next(ls);
+          continue;
+        }
+        else if (isdigit(ls->current)) {
+          read_numeral(ls, seminfo);
+          return TK_NUMBER;
+        }
+        else if (isalpha(ls->current) || ls->current == '_') {
+          /* identifier or reserved word */
+          TString *ts;
+          do {
+            save_and_next(ls);
+          } while (isalnum(ls->current) || ls->current == '_');
+          ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
+                                  luaZ_bufflen(ls->buff));
+          if (ts->tsv.reserved > 0)  /* reserved word? */
+            return ts->tsv.reserved - 1 + FIRST_RESERVED;
+          else {
+            seminfo->ts = ts;
+            return TK_NAME;
+          }
+        }
+        else {
+          int c = ls->current;
+          next(ls);
+          return c;  /* single-char tokens (+ - / ...) */
+        }
+      }
+    }
+  }
+}
+
+
+void luaX_next (LexState *ls) {
+  ls->lastline = ls->linenumber;
+  if (ls->lookahead.token != TK_EOS) {  /* is there a look-ahead token? */
+    ls->t = ls->lookahead;  /* use this one */
+    ls->lookahead.token = TK_EOS;  /* and discharge it */
+  }
+  else
+    ls->t.token = llex(ls, &ls->t.seminfo);  /* read next token */
+}
+
+
+void luaX_lookahead (LexState *ls) {
+  lua_assert(ls->lookahead.token == TK_EOS);
+  ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
+}
+

=== added file 'lua/llex.h'
--- lua/llex.h	1970-01-01 00:00:00 +0000
+++ lua/llex.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,81 @@
+/*
+** $Id: llex.h,v 1.58.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lexical Analyzer
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llex_h
+#define llex_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+
+#define FIRST_RESERVED	257
+
+/* maximum length of a reserved word */
+#define TOKEN_LEN	(sizeof("function")/sizeof(char))
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER RESERVED"
+*/
+enum RESERVED {
+  /* terminal symbols denoted by reserved words */
+  TK_AND = FIRST_RESERVED, TK_BREAK,
+  TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
+  TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+  TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
+  /* other terminal symbols */
+  TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
+  TK_NAME, TK_STRING, TK_EOS
+};
+
+/* number of reserved words */
+#define NUM_RESERVED	(cast(int, TK_WHILE-FIRST_RESERVED+1))
+
+
+/* array with token `names' */
+LUAI_DATA const char *const luaX_tokens [];
+
+
+typedef union {
+  lua_Number r;
+  TString *ts;
+} SemInfo;  /* semantics information */
+
+
+typedef struct Token {
+  int token;
+  SemInfo seminfo;
+} Token;
+
+
+typedef struct LexState {
+  int current;  /* current character (charint) */
+  int linenumber;  /* input line counter */
+  int lastline;  /* line of last token `consumed' */
+  Token t;  /* current token */
+  Token lookahead;  /* look ahead token */
+  struct FuncState *fs;  /* `FuncState' is private to the parser */
+  struct lua_State *L;
+  ZIO *z;  /* input stream */
+  Mbuffer *buff;  /* buffer for tokens */
+  TString *source;  /* current source name */
+  char decpoint;  /* locale decimal point */
+} LexState;
+
+
+LUAI_FUNC void luaX_init (lua_State *L);
+LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
+                              TString *source);
+LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
+LUAI_FUNC void luaX_next (LexState *ls);
+LUAI_FUNC void luaX_lookahead (LexState *ls);
+LUAI_FUNC void luaX_lexerror (LexState *ls, const char *msg, int token);
+LUAI_FUNC void luaX_syntaxerror (LexState *ls, const char *s);
+LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
+
+
+#endif

=== added file 'lua/llimits.h'
--- lua/llimits.h	1970-01-01 00:00:00 +0000
+++ lua/llimits.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,136 @@
+/*
+** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $
+** Limits, basic types, and some other `installation-dependent' definitions
+** See Copyright Notice in lua.h
+*/
+
+#ifndef llimits_h
+#define llimits_h
+
+
+#ifndef USE_GRUB_LIB
+#include <limits.h>
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+
+#include "lua.h"
+
+
+typedef LUAI_UINT32 lu_int32;
+
+typedef LUAI_UMEM lu_mem;
+
+typedef LUAI_MEM l_mem;
+
+
+
+/* chars used as small naturals (so that `char' is reserved for characters) */
+typedef unsigned char lu_byte;
+
+
+#define MAX_SIZET	((size_t)(~(size_t)0)-2)
+
+#define MAX_LUMEM	((lu_mem)(~(lu_mem)0)-2)
+
+
+#define MAX_INT (INT_MAX-2)  /* maximum value of an int (-2 for safety) */
+
+/*
+** conversion of pointer to integer
+** this is for hashing only; there is no problem if the integer
+** cannot hold the whole pointer value
+*/
+#define IntPoint(p)  ((unsigned int)(lu_mem)(p))
+
+
+
+/* type to ensure maximum alignment */
+typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
+
+
+/* result of a `usual argument conversion' over lua_Number */
+typedef LUAI_UACNUMBER l_uacNumber;
+
+
+/* internal assertions for in-house debugging */
+#ifdef lua_assert
+
+#define check_exp(c,e)		(lua_assert(c), (e))
+#define api_check(l,e)		lua_assert(e)
+
+#else
+
+#define lua_assert(c)		((void)0)
+#define check_exp(c,e)		(e)
+#define api_check		luai_apicheck
+
+#endif
+
+
+#ifdef USE_GRUB_LIB
+/* Redefine UNUSED:  GRUB uses it as an attribute within the parameter 
+   list, but LUA uses it as a statement in the function body.  */
+#undef UNUSED
+#endif /* USE_GRUB_LIB */
+
+#ifndef UNUSED
+#define UNUSED(x)	((void)(x))	/* to avoid warnings */
+#endif
+
+
+#ifndef cast
+#define cast(t, exp)	((t)(exp))
+#endif
+
+#define cast_byte(i)	cast(lu_byte, (i))
+#define cast_num(i)	cast(lua_Number, (i))
+#define cast_int(i)	cast(int, (i))
+
+
+
+/*
+** type for virtual-machine instructions
+** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
+*/
+typedef lu_int32 Instruction;
+
+
+
+/* maximum stack for a Lua function */
+#define MAXSTACK	250
+
+
+
+/* minimum size for the string table (must be power of 2) */
+#ifndef MINSTRTABSIZE
+#define MINSTRTABSIZE	32
+#endif
+
+
+/* minimum size for string buffer */
+#ifndef LUA_MINBUFFER
+#define LUA_MINBUFFER	32
+#endif
+
+
+#ifndef lua_lock
+#define lua_lock(L)     ((void) 0) 
+#define lua_unlock(L)   ((void) 0)
+#endif
+
+#ifndef luai_threadyield
+#define luai_threadyield(L)     {lua_unlock(L); lua_lock(L);}
+#endif
+
+
+/*
+** macro to control inclusion of some hard tests on stack reallocation
+*/ 
+#ifndef HARDSTACKTESTS
+#define condhardstacktests(x)	((void)0)
+#else
+#define condhardstacktests(x)	x
+#endif
+
+#endif

=== added file 'lua/lmathlib.c'
--- lua/lmathlib.c	1970-01-01 00:00:00 +0000
+++ lua/lmathlib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,267 @@
+/*
+** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $
+** Standard mathematical library
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stdlib.h>
+#include <math.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lmathlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#undef PI
+#define PI (3.14159265358979323846)
+#define RADIANS_PER_DEGREE (PI/180.0)
+
+
+
+static int math_abs (lua_State *L) {
+  lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_sin (lua_State *L) {
+  lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_sinh (lua_State *L) {
+  lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_cos (lua_State *L) {
+  lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_cosh (lua_State *L) {
+  lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_tan (lua_State *L) {
+  lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_tanh (lua_State *L) {
+  lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_asin (lua_State *L) {
+  lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_acos (lua_State *L) {
+  lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_atan (lua_State *L) {
+  lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_atan2 (lua_State *L) {
+  lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+  return 1;
+}
+
+static int math_ceil (lua_State *L) {
+  lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_floor (lua_State *L) {
+  lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_fmod (lua_State *L) {
+  lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+  return 1;
+}
+
+static int math_modf (lua_State *L) {
+  double ip;
+  double fp = modf(luaL_checknumber(L, 1), &ip);
+  lua_pushnumber(L, ip);
+  lua_pushnumber(L, fp);
+  return 2;
+}
+
+static int math_sqrt (lua_State *L) {
+  lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_pow (lua_State *L) {
+  lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
+  return 1;
+}
+
+static int math_log (lua_State *L) {
+  lua_pushnumber(L, log(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_log10 (lua_State *L) {
+  lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_exp (lua_State *L) {
+  lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
+  return 1;
+}
+
+static int math_deg (lua_State *L) {
+  lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
+  return 1;
+}
+
+static int math_rad (lua_State *L) {
+  lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
+  return 1;
+}
+
+static int math_frexp (lua_State *L) {
+  int e;
+  lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
+  lua_pushinteger(L, e);
+  return 2;
+}
+
+static int math_ldexp (lua_State *L) {
+  lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
+  return 1;
+}
+
+
+
+static int math_min (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  lua_Number dmin = luaL_checknumber(L, 1);
+  int i;
+  for (i=2; i<=n; i++) {
+    lua_Number d = luaL_checknumber(L, i);
+    if (d < dmin)
+      dmin = d;
+  }
+  lua_pushnumber(L, dmin);
+  return 1;
+}
+
+
+static int math_max (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  lua_Number dmax = luaL_checknumber(L, 1);
+  int i;
+  for (i=2; i<=n; i++) {
+    lua_Number d = luaL_checknumber(L, i);
+    if (d > dmax)
+      dmax = d;
+  }
+  lua_pushnumber(L, dmax);
+  return 1;
+}
+
+
+static int math_random (lua_State *L) {
+  /* the `%' avoids the (rare) case of r==1, and is needed also because on
+     some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+  lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
+  switch (lua_gettop(L)) {  /* check number of arguments */
+    case 0: {  /* no arguments */
+      lua_pushnumber(L, r);  /* Number between 0 and 1 */
+      break;
+    }
+    case 1: {  /* only upper limit */
+      int u = luaL_checkint(L, 1);
+      luaL_argcheck(L, 1<=u, 1, "interval is empty");
+      lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */
+      break;
+    }
+    case 2: {  /* lower and upper limits */
+      int l = luaL_checkint(L, 1);
+      int u = luaL_checkint(L, 2);
+      luaL_argcheck(L, l<=u, 2, "interval is empty");
+      lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */
+      break;
+    }
+    default: return luaL_error(L, "wrong number of arguments");
+  }
+  return 1;
+}
+
+
+static int math_randomseed (lua_State *L) {
+  srand(luaL_checkint(L, 1));
+  return 0;
+}
+
+
+static const luaL_Reg mathlib[] = {
+  {"abs",   math_abs},
+  {"acos",  math_acos},
+  {"asin",  math_asin},
+  {"atan2", math_atan2},
+  {"atan",  math_atan},
+  {"ceil",  math_ceil},
+  {"cosh",   math_cosh},
+  {"cos",   math_cos},
+  {"deg",   math_deg},
+  {"exp",   math_exp},
+  {"floor", math_floor},
+  {"fmod",   math_fmod},
+  {"frexp", math_frexp},
+  {"ldexp", math_ldexp},
+  {"log10", math_log10},
+  {"log",   math_log},
+  {"max",   math_max},
+  {"min",   math_min},
+  {"modf",   math_modf},
+  {"pow",   math_pow},
+  {"rad",   math_rad},
+  {"random",     math_random},
+  {"randomseed", math_randomseed},
+  {"sinh",   math_sinh},
+  {"sin",   math_sin},
+  {"sqrt",  math_sqrt},
+  {"tanh",   math_tanh},
+  {"tan",   math_tan},
+  {NULL, NULL}
+};
+
+
+/*
+** Open math library
+*/
+LUALIB_API int luaopen_math (lua_State *L) {
+  luaL_register(L, LUA_MATHLIBNAME, mathlib);
+  lua_pushnumber(L, PI);
+  lua_setfield(L, -2, "pi");
+#if !defined LUA_NUMBER_INTEGRAL
+  lua_pushnumber(L, HUGE_VAL);
+  lua_setfield(L, -2, "huge");
+#endif
+#if defined(LUA_COMPAT_MOD)
+  lua_getfield(L, -1, "fmod");
+  lua_setfield(L, -2, "mod");
+#endif
+  return 1;
+}
+

=== added file 'lua/lmem.c'
--- lua/lmem.c	1970-01-01 00:00:00 +0000
+++ lua/lmem.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,88 @@
+/*
+** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lmem_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+
+/*
+** About the realloc function:
+** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
+** (`osize' is the old size, `nsize' is the new size)
+**
+** Lua ensures that (ptr == NULL) iff (osize == 0).
+**
+** * frealloc(ud, NULL, 0, x) creates a new block of size `x'
+**
+** * frealloc(ud, p, x, 0) frees the block `p'
+** (in this specific case, frealloc must return NULL).
+** particularly, frealloc(ud, NULL, 0, 0) does nothing
+** (which is equivalent to free(NULL) in ANSI C)
+**
+** frealloc returns NULL if it cannot create or reallocate the area
+** (any reallocation to an equal or smaller size cannot fail!)
+*/
+
+
+
+#define MINSIZEARRAY	4
+
+
+void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
+                     int limit, const char *errormsg) {
+  void *newblock;
+  int newsize;
+  if (*size >= limit/2) {  /* cannot double it? */
+    if (*size >= limit)  /* cannot grow even a little? */
+      luaG_runerror(L, errormsg);
+    newsize = limit;  /* still have at least one free place */
+  }
+  else {
+    newsize = (*size)*2;
+    if (newsize < MINSIZEARRAY)
+      newsize = MINSIZEARRAY;  /* minimum size */
+  }
+  newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
+  *size = newsize;  /* update only when everything else is OK */
+  return newblock;
+}
+
+
+void *luaM_toobig (lua_State *L) {
+  luaG_runerror(L, "memory allocation error: block too big");
+  return NULL;  /* to avoid warnings */
+}
+
+
+
+/*
+** generic allocation routine.
+*/
+void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
+  global_State *g = G(L);
+  lua_assert((osize == 0) == (block == NULL));
+  block = (*g->frealloc)(g->ud, block, osize, nsize);
+  if (block == NULL && nsize > 0)
+    luaD_throw(L, LUA_ERRMEM);
+  lua_assert((nsize == 0) == (block == NULL));
+  g->totalbytes = (g->totalbytes - osize) + nsize;
+  return block;
+}
+

=== added file 'lua/lmem.h'
--- lua/lmem.h	1970-01-01 00:00:00 +0000
+++ lua/lmem.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,51 @@
+/*
+** $Id: lmem.h,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
+** Interface to Memory Manager
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lmem_h
+#define lmem_h
+
+
+#ifndef USE_GRUB_LIB
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+#include "llimits.h"
+#include "lua.h"
+
+#define MEMERRMSG	"not enough memory"
+
+
+#define luaM_reallocv(L,b,on,n,e) \
+	((cast(size_t, (n)+1) <= MAX_SIZET/(e)) ?  /* +1 to avoid warnings */ \
+		luaM_realloc_(L, (b), (on)*(e), (n)*(e)) : \
+		luaM_toobig(L))
+
+#define luaM_freemem(L, b, s)	luaM_realloc_(L, (b), (s), 0)
+#define luaM_free(L, b)		luaM_realloc_(L, (b), sizeof(*(b)), 0)
+#define luaM_freearray(L, b, n, t)   luaM_reallocv(L, (b), n, 0, sizeof(t))
+
+#define luaM_malloc(L,t)	luaM_realloc_(L, NULL, 0, (t))
+#define luaM_new(L,t)		cast(t *, luaM_malloc(L, sizeof(t)))
+#define luaM_newvector(L,n,t) \
+		cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
+
+#define luaM_growvector(L,v,nelems,size,t,limit,e) \
+          if ((nelems)+1 > (size)) \
+            ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+
+#define luaM_reallocvector(L, v,oldn,n,t) \
+   ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
+
+
+LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
+                                                          size_t size);
+LUAI_FUNC void *luaM_toobig (lua_State *L);
+LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
+                               size_t size_elem, int limit,
+                               const char *errormsg);
+
+#endif
+

=== added file 'lua/loadlib.c'
--- lua/loadlib.c	1970-01-01 00:00:00 +0000
+++ lua/loadlib.c	2008-08-01 15:19:23 +0000
@@ -0,0 +1,664 @@
+/*
+** $Id: loadlib.c,v 1.52.1.2 2007/12/28 14:58:43 roberto Exp $
+** Dynamic library loader for Lua
+** See Copyright Notice in lua.h
+**
+** This module contains an implementation of loadlib for Unix systems
+** that have dlfcn, an implementation for Darwin (Mac OS X), an
+** implementation for Windows, and a stub for other systems.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#define loadlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/* prefix for open functions in C libraries */
+#define LUA_POF		"luaopen_"
+
+/* separator for open functions in C libraries */
+#define LUA_OFSEP	"_"
+
+
+#define LIBPREFIX	"LOADLIB: "
+
+#define POF		LUA_POF
+#define LIB_FAIL	"open"
+
+
+/* error codes for ll_loadfunc */
+#define ERRLIB		1
+#define ERRFUNC		2
+
+#define setprogdir(L)		((void)0)
+
+
+static void ll_unloadlib (void *lib);
+static void *ll_load (lua_State *L, const char *path);
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
+
+
+
+#if defined(LUA_DL_DLOPEN)
+/*
+** {========================================================================
+** This is an implementation of loadlib based on the dlfcn interface.
+** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least
+** as an emulation layer on top of native functions.
+** =========================================================================
+*/
+
+#include <dlfcn.h>
+
+static void ll_unloadlib (void *lib) {
+  dlclose(lib);
+}
+
+
+static void *ll_load (lua_State *L, const char *path) {
+  void *lib = dlopen(path, RTLD_NOW);
+  if (lib == NULL) lua_pushstring(L, dlerror());
+  return lib;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
+  if (f == NULL) lua_pushstring(L, dlerror());
+  return f;
+}
+
+/* }====================================================== */
+
+
+
+#elif defined(LUA_DL_DLL)
+/*
+** {======================================================================
+** This is an implementation of loadlib for Windows using native functions.
+** =======================================================================
+*/
+
+#include <windows.h>
+
+
+#undef setprogdir
+
+static void setprogdir (lua_State *L) {
+  char buff[MAX_PATH + 1];
+  char *lb;
+  DWORD nsize = sizeof(buff)/sizeof(char);
+  DWORD n = GetModuleFileNameA(NULL, buff, nsize);
+  if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
+    luaL_error(L, "unable to get ModuleFileName");
+  else {
+    *lb = '\0';
+    luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
+    lua_remove(L, -2);  /* remove original string */
+  }
+}
+
+
+static void pusherror (lua_State *L) {
+  int error = GetLastError();
+  char buffer[128];
+  if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+      NULL, error, 0, buffer, sizeof(buffer), NULL))
+    lua_pushstring(L, buffer);
+  else
+    lua_pushfstring(L, "system error %d\n", error);
+}
+
+static void ll_unloadlib (void *lib) {
+  FreeLibrary((HINSTANCE)lib);
+}
+
+
+static void *ll_load (lua_State *L, const char *path) {
+  HINSTANCE lib = LoadLibraryA(path);
+  if (lib == NULL) pusherror(L);
+  return lib;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
+  if (f == NULL) pusherror(L);
+  return f;
+}
+
+/* }====================================================== */
+
+
+
+#elif defined(LUA_DL_DYLD)
+/*
+** {======================================================================
+** Native Mac OS X / Darwin Implementation
+** =======================================================================
+*/
+
+#include <mach-o/dyld.h>
+
+
+/* Mac appends a `_' before C function names */
+#undef POF
+#define POF	"_" LUA_POF
+
+
+static void pusherror (lua_State *L) {
+  const char *err_str;
+  const char *err_file;
+  NSLinkEditErrors err;
+  int err_num;
+  NSLinkEditError(&err, &err_num, &err_file, &err_str);
+  lua_pushstring(L, err_str);
+}
+
+
+static const char *errorfromcode (NSObjectFileImageReturnCode ret) {
+  switch (ret) {
+    case NSObjectFileImageInappropriateFile:
+      return "file is not a bundle";
+    case NSObjectFileImageArch:
+      return "library is for wrong CPU type";
+    case NSObjectFileImageFormat:
+      return "bad format";
+    case NSObjectFileImageAccess:
+      return "cannot access file";
+    case NSObjectFileImageFailure:
+    default:
+      return "unable to load library";
+  }
+}
+
+
+static void ll_unloadlib (void *lib) {
+  NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
+}
+
+
+static void *ll_load (lua_State *L, const char *path) {
+  NSObjectFileImage img;
+  NSObjectFileImageReturnCode ret;
+  /* this would be a rare case, but prevents crashing if it happens */
+  if(!_dyld_present()) {
+    lua_pushliteral(L, "dyld not present");
+    return NULL;
+  }
+  ret = NSCreateObjectFileImageFromFile(path, &img);
+  if (ret == NSObjectFileImageSuccess) {
+    NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE |
+                       NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+    NSDestroyObjectFileImage(img);
+    if (mod == NULL) pusherror(L);
+    return mod;
+  }
+  lua_pushstring(L, errorfromcode(ret));
+  return NULL;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
+  if (nss == NULL) {
+    lua_pushfstring(L, "symbol " LUA_QS " not found", sym);
+    return NULL;
+  }
+  return (lua_CFunction)NSAddressOfSymbol(nss);
+}
+
+/* }====================================================== */
+
+
+
+#else
+/*
+** {======================================================
+** Fallback for other systems
+** =======================================================
+*/
+
+#undef LIB_FAIL
+#define LIB_FAIL	"absent"
+
+
+#define DLMSG	"dynamic libraries not enabled; check your Lua installation"
+
+
+static void ll_unloadlib (void *lib) {
+  (void)lib;  /* to avoid warnings */
+}
+
+
+static void *ll_load (lua_State *L, const char *path) {
+  (void)path;  /* to avoid warnings */
+  lua_pushliteral(L, DLMSG);
+  return NULL;
+}
+
+
+static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
+  (void)lib; (void)sym;  /* to avoid warnings */
+  lua_pushliteral(L, DLMSG);
+  return NULL;
+}
+
+/* }====================================================== */
+#endif
+
+
+
+static void **ll_register (lua_State *L, const char *path) {
+  void **plib;
+  lua_pushfstring(L, "%s%s", LIBPREFIX, path);
+  lua_gettable(L, LUA_REGISTRYINDEX);  /* check library in registry? */
+  if (!lua_isnil(L, -1))  /* is there an entry? */
+    plib = (void **)lua_touserdata(L, -1);
+  else {  /* no entry yet; create one */
+    lua_pop(L, 1);
+    plib = (void **)lua_newuserdata(L, sizeof(const void *));
+    *plib = NULL;
+    luaL_getmetatable(L, "_LOADLIB");
+    lua_setmetatable(L, -2);
+    lua_pushfstring(L, "%s%s", LIBPREFIX, path);
+    lua_pushvalue(L, -2);
+    lua_settable(L, LUA_REGISTRYINDEX);
+  }
+  return plib;
+}
+
+
+/*
+** __gc tag method: calls library's `ll_unloadlib' function with the lib
+** handle
+*/
+static int gctm (lua_State *L) {
+  void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
+  if (*lib) ll_unloadlib(*lib);
+  *lib = NULL;  /* mark library as closed */
+  return 0;
+}
+
+
+static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
+  void **reg = ll_register(L, path);
+  if (*reg == NULL) *reg = ll_load(L, path);
+  if (*reg == NULL)
+    return ERRLIB;  /* unable to load library */
+  else {
+    lua_CFunction f = ll_sym(L, *reg, sym);
+    if (f == NULL)
+      return ERRFUNC;  /* unable to find function */
+    lua_pushcfunction(L, f);
+    return 0;  /* return function */
+  }
+}
+
+
+static int ll_loadlib (lua_State *L) {
+  const char *path = luaL_checkstring(L, 1);
+  const char *init = luaL_checkstring(L, 2);
+  int stat = ll_loadfunc(L, path, init);
+  if (stat == 0)  /* no errors? */
+    return 1;  /* return the loaded function */
+  else {  /* error; error message is on stack top */
+    lua_pushnil(L);
+    lua_insert(L, -2);
+    lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init");
+    return 3;  /* return nil, error message, and where */
+  }
+}
+
+
+
+/*
+** {======================================================
+** 'require' function
+** =======================================================
+*/
+
+
+static int readable (const char *filename) {
+  FILE *f = fopen(filename, "r");  /* try to open file */
+  if (f == NULL) return 0;  /* open failed */
+  fclose(f);
+  return 1;
+}
+
+
+static const char *pushnexttemplate (lua_State *L, const char *path) {
+  const char *l;
+  while (*path == *LUA_PATHSEP) path++;  /* skip separators */
+  if (*path == '\0') return NULL;  /* no more templates */
+  l = strchr(path, *LUA_PATHSEP);  /* find next separator */
+  if (l == NULL) l = path + strlen(path);
+  lua_pushlstring(L, path, l - path);  /* template */
+  return l;
+}
+
+
+static const char *findfile (lua_State *L, const char *name,
+                                           const char *pname) {
+  const char *path;
+  name = luaL_gsub(L, name, ".", LUA_DIRSEP);
+  lua_getfield(L, LUA_ENVIRONINDEX, pname);
+  path = lua_tostring(L, -1);
+  if (path == NULL)
+    luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
+  lua_pushliteral(L, "");  /* error accumulator */
+  while ((path = pushnexttemplate(L, path)) != NULL) {
+    const char *filename;
+    filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
+    lua_remove(L, -2);  /* remove path template */
+    if (readable(filename))  /* does file exist and is readable? */
+      return filename;  /* return that file name */
+    lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
+    lua_remove(L, -2);  /* remove file name */
+    lua_concat(L, 2);  /* add entry to possible error message */
+  }
+  return NULL;  /* not found */
+}
+
+
+static void loaderror (lua_State *L, const char *filename) {
+  luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
+                lua_tostring(L, 1), filename, lua_tostring(L, -1));
+}
+
+
+static int loader_Lua (lua_State *L) {
+  const char *filename;
+  const char *name = luaL_checkstring(L, 1);
+  filename = findfile(L, name, "path");
+  if (filename == NULL) return 1;  /* library not found in this path */
+  if (luaL_loadfile(L, filename) != 0)
+    loaderror(L, filename);
+  return 1;  /* library loaded successfully */
+}
+
+
+static const char *mkfuncname (lua_State *L, const char *modname) {
+  const char *funcname;
+  const char *mark = strchr(modname, *LUA_IGMARK);
+  if (mark) modname = mark + 1;
+  funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
+  funcname = lua_pushfstring(L, POF"%s", funcname);
+  lua_remove(L, -2);  /* remove 'gsub' result */
+  return funcname;
+}
+
+
+static int loader_C (lua_State *L) {
+  const char *funcname;
+  const char *name = luaL_checkstring(L, 1);
+  const char *filename = findfile(L, name, "cpath");
+  if (filename == NULL) return 1;  /* library not found in this path */
+  funcname = mkfuncname(L, name);
+  if (ll_loadfunc(L, filename, funcname) != 0)
+    loaderror(L, filename);
+  return 1;  /* library loaded successfully */
+}
+
+
+static int loader_Croot (lua_State *L) {
+  const char *funcname;
+  const char *filename;
+  const char *name = luaL_checkstring(L, 1);
+  const char *p = strchr(name, '.');
+  int stat;
+  if (p == NULL) return 0;  /* is root */
+  lua_pushlstring(L, name, p - name);
+  filename = findfile(L, lua_tostring(L, -1), "cpath");
+  if (filename == NULL) return 1;  /* root not found */
+  funcname = mkfuncname(L, name);
+  if ((stat = ll_loadfunc(L, filename, funcname)) != 0) {
+    if (stat != ERRFUNC) loaderror(L, filename);  /* real error */
+    lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
+                       name, filename);
+    return 1;  /* function not found */
+  }
+  return 1;
+}
+
+
+static int loader_preload (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
+  lua_getfield(L, LUA_ENVIRONINDEX, "preload");
+  if (!lua_istable(L, -1))
+    luaL_error(L, LUA_QL("package.preload") " must be a table");
+  lua_getfield(L, -1, name);
+  if (lua_isnil(L, -1))  /* not found? */
+    lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
+  return 1;
+}
+
+
+static const int sentinel_ = 0;
+#define sentinel	((void *)&sentinel_)
+
+
+static int ll_require (lua_State *L) {
+  const char *name = luaL_checkstring(L, 1);
+  int i;
+  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
+  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_getfield(L, 2, name);
+  if (lua_toboolean(L, -1)) {  /* is it there? */
+    if (lua_touserdata(L, -1) == sentinel)  /* check loops */
+      luaL_error(L, "loop or previous error loading module " LUA_QS, name);
+    return 1;  /* package is already loaded */
+  }
+  /* else must load it; iterate over available loaders */
+  lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
+  if (!lua_istable(L, -1))
+    luaL_error(L, LUA_QL("package.loaders") " must be a table");
+  lua_pushliteral(L, "");  /* error message accumulator */
+  for (i=1; ; i++) {
+    lua_rawgeti(L, -2, i);  /* get a loader */
+    if (lua_isnil(L, -1))
+      luaL_error(L, "module " LUA_QS " not found:%s",
+                    name, lua_tostring(L, -2));
+    lua_pushstring(L, name);
+    lua_call(L, 1, 1);  /* call it */
+    if (lua_isfunction(L, -1))  /* did it find module? */
+      break;  /* module loaded successfully */
+    else if (lua_isstring(L, -1))  /* loader returned error message? */
+      lua_concat(L, 2);  /* accumulate it */
+    else
+      lua_pop(L, 1);
+  }
+  lua_pushlightuserdata(L, sentinel);
+  lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */
+  lua_pushstring(L, name);  /* pass name as argument to module */
+  lua_call(L, 1, 1);  /* run loaded module */
+  if (!lua_isnil(L, -1))  /* non-nil return? */
+    lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
+  lua_getfield(L, 2, name);
+  if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */
+    lua_pushboolean(L, 1);  /* use true as result */
+    lua_pushvalue(L, -1);  /* extra copy to be returned */
+    lua_setfield(L, 2, name);  /* _LOADED[name] = true */
+  }
+  return 1;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** 'module' function
+** =======================================================
+*/
+  
+
+static void setfenv (lua_State *L) {
+  lua_Debug ar;
+  lua_getstack(L, 1, &ar);
+  lua_getinfo(L, "f", &ar);
+  lua_pushvalue(L, -2);
+  lua_setfenv(L, -2);
+  lua_pop(L, 1);
+}
+
+
+static void dooptions (lua_State *L, int n) {
+  int i;
+  for (i = 2; i <= n; i++) {
+    lua_pushvalue(L, i);  /* get option (a function) */
+    lua_pushvalue(L, -2);  /* module */
+    lua_call(L, 1, 0);
+  }
+}
+
+
+static void modinit (lua_State *L, const char *modname) {
+  const char *dot;
+  lua_pushvalue(L, -1);
+  lua_setfield(L, -2, "_M");  /* module._M = module */
+  lua_pushstring(L, modname);
+  lua_setfield(L, -2, "_NAME");
+  dot = strrchr(modname, '.');  /* look for last dot in module name */
+  if (dot == NULL) dot = modname;
+  else dot++;
+  /* set _PACKAGE as package name (full module name minus last part) */
+  lua_pushlstring(L, modname, dot - modname);
+  lua_setfield(L, -2, "_PACKAGE");
+}
+
+
+static int ll_module (lua_State *L) {
+  const char *modname = luaL_checkstring(L, 1);
+  int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */
+  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+  lua_getfield(L, loaded, modname);  /* get _LOADED[modname] */
+  if (!lua_istable(L, -1)) {  /* not found? */
+    lua_pop(L, 1);  /* remove previous result */
+    /* try global variable (and create one if it does not exist) */
+    if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
+      return luaL_error(L, "name conflict for module " LUA_QS, modname);
+    lua_pushvalue(L, -1);
+    lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */
+  }
+  /* check whether table already has a _NAME field */
+  lua_getfield(L, -1, "_NAME");
+  if (!lua_isnil(L, -1))  /* is table an initialized module? */
+    lua_pop(L, 1);
+  else {  /* no; initialize it */
+    lua_pop(L, 1);
+    modinit(L, modname);
+  }
+  lua_pushvalue(L, -1);
+  setfenv(L);
+  dooptions(L, loaded - 1);
+  return 0;
+}
+
+
+static int ll_seeall (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  if (!lua_getmetatable(L, 1)) {
+    lua_createtable(L, 0, 1); /* create new metatable */
+    lua_pushvalue(L, -1);
+    lua_setmetatable(L, 1);
+  }
+  lua_pushvalue(L, LUA_GLOBALSINDEX);
+  lua_setfield(L, -2, "__index");  /* mt.__index = _G */
+  return 0;
+}
+
+
+/* }====================================================== */
+
+
+
+/* auxiliary mark (for internal use) */
+#define AUXMARK		"\1"
+
+static void setpath (lua_State *L, const char *fieldname, const char *envname,
+                                   const char *def) {
+  const char *path = getenv(envname);
+  if (path == NULL)  /* no environment variable? */
+    lua_pushstring(L, def);  /* use default */
+  else {
+    /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
+    path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
+                              LUA_PATHSEP AUXMARK LUA_PATHSEP);
+    luaL_gsub(L, path, AUXMARK, def);
+    lua_remove(L, -2);
+  }
+  setprogdir(L);
+  lua_setfield(L, -2, fieldname);
+}
+
+
+static const luaL_Reg pk_funcs[] = {
+  {"loadlib", ll_loadlib},
+  {"seeall", ll_seeall},
+  {NULL, NULL}
+};
+
+
+static const luaL_Reg ll_funcs[] = {
+  {"module", ll_module},
+  {"require", ll_require},
+  {NULL, NULL}
+};
+
+
+static const lua_CFunction loaders[] =
+  {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
+
+
+LUALIB_API int luaopen_package (lua_State *L) {
+  int i;
+  /* create new type _LOADLIB */
+  luaL_newmetatable(L, "_LOADLIB");
+  lua_pushcfunction(L, gctm);
+  lua_setfield(L, -2, "__gc");
+  /* create `package' table */
+  luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
+#if defined(LUA_COMPAT_LOADLIB) 
+  lua_getfield(L, -1, "loadlib");
+  lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
+#endif
+  lua_pushvalue(L, -1);
+  lua_replace(L, LUA_ENVIRONINDEX);
+  /* create `loaders' table */
+  lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);
+  /* fill it with pre-defined loaders */
+  for (i=0; loaders[i] != NULL; i++) {
+    lua_pushcfunction(L, loaders[i]);
+    lua_rawseti(L, -2, i+1);
+  }
+  lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */
+  setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT);  /* set field `path' */
+  setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
+  /* store config information */
+  lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
+                     LUA_EXECDIR "\n" LUA_IGMARK);
+  lua_setfield(L, -2, "config");
+  /* set field `loaded' */
+  luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
+  lua_setfield(L, -2, "loaded");
+  /* set field `preload' */
+  lua_newtable(L);
+  lua_setfield(L, -2, "preload");
+  lua_pushvalue(L, LUA_GLOBALSINDEX);
+  luaL_register(L, NULL, ll_funcs);  /* open lib into global table */
+  lua_pop(L, 1);
+  return 1;  /* return 'package' table */
+}
+

=== added file 'lua/lobject.c'
--- lua/lobject.c	1970-01-01 00:00:00 +0000
+++ lua/lobject.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,216 @@
+/*
+** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $
+** Some generic functions over Lua objects
+** See Copyright Notice in lua.h
+*/
+
+#ifndef USE_GRUB_LIB
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lobject_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldo.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "lvm.h"
+
+
+
+const TValue luaO_nilobject_ = {{NULL}, LUA_TNIL};
+
+
+/*
+** converts an integer to a "floating point byte", represented as
+** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
+** eeeee != 0 and (xxx) otherwise.
+*/
+int luaO_int2fb (unsigned int x) {
+  int e = 0;  /* expoent */
+  while (x >= 16) {
+    x = (x+1) >> 1;
+    e++;
+  }
+  if (x < 8) return x;
+  else return ((e+1) << 3) | (cast_int(x) - 8);
+}
+
+
+/* converts back */
+int luaO_fb2int (int x) {
+  int e = (x >> 3) & 31;
+  if (e == 0) return x;
+  else return ((x & 7)+8) << (e - 1);
+}
+
+
+int luaO_log2 (unsigned int x) {
+  static const lu_byte log_2[256] = {
+    0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+  };
+  int l = -1;
+  while (x >= 256) { l += 8; x >>= 8; }
+  return l + log_2[x];
+
+}
+
+
+int luaO_rawequalObj (const TValue *t1, const TValue *t2) {
+  if (ttype(t1) != ttype(t2)) return 0;
+  else switch (ttype(t1)) {
+    case LUA_TNIL:
+      return 1;
+    case LUA_TNUMBER:
+      return luai_numeq(nvalue(t1), nvalue(t2));
+    case LUA_TBOOLEAN:
+      return bvalue(t1) == bvalue(t2);  /* boolean true must be 1 !! */
+    case LUA_TLIGHTUSERDATA:
+      return pvalue(t1) == pvalue(t2);
+    default:
+      lua_assert(iscollectable(t1));
+      return gcvalue(t1) == gcvalue(t2);
+  }
+}
+
+
+int luaO_str2d (const char *s, lua_Number *result) {
+  char *endptr;
+  *result = lua_str2number(s, &endptr);
+  if (endptr == s) return 0;  /* conversion failed */
+  if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */
+    *result = cast_num(strtoul(s, &endptr, 16));
+  if (*endptr == '\0') return 1;  /* most common case */
+  while (isspace(cast(unsigned char, *endptr))) endptr++;
+  if (*endptr != '\0') return 0;  /* invalid trailing characters? */
+  return 1;
+}
+
+
+
+static void pushstr (lua_State *L, const char *str) {
+  setsvalue2s(L, L->top, luaS_new(L, str));
+  incr_top(L);
+}
+
+
+/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
+const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
+  int n = 1;
+  pushstr(L, "");
+  for (;;) {
+    const char *e = strchr(fmt, '%');
+    if (e == NULL) break;
+    setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt));
+    incr_top(L);
+    switch (*(e+1)) {
+      case 's': {
+        const char *s = va_arg(argp, char *);
+        if (s == NULL) s = "(null)";
+        pushstr(L, s);
+        break;
+      }
+      case 'c': {
+        char buff[2];
+        buff[0] = cast(char, va_arg(argp, int));
+        buff[1] = '\0';
+        pushstr(L, buff);
+        break;
+      }
+      case 'd': {
+        setnvalue(L->top, cast_num(va_arg(argp, int)));
+        incr_top(L);
+        break;
+      }
+      case 'f': {
+        setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
+        incr_top(L);
+        break;
+      }
+      case 'p': {
+        char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
+        sprintf(buff, "%p", va_arg(argp, void *));
+        pushstr(L, buff);
+        break;
+      }
+      case '%': {
+        pushstr(L, "%");
+        break;
+      }
+      default: {
+        char buff[3];
+        buff[0] = '%';
+        buff[1] = *(e+1);
+        buff[2] = '\0';
+        pushstr(L, buff);
+        break;
+      }
+    }
+    n += 2;
+    fmt = e+2;
+  }
+  pushstr(L, fmt);
+  luaV_concat(L, n+1, cast_int(L->top - L->base) - 1);
+  L->top -= n;
+  return svalue(L->top - 1);
+}
+
+
+const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
+  const char *msg;
+  va_list argp;
+  va_start(argp, fmt);
+  msg = luaO_pushvfstring(L, fmt, argp);
+  va_end(argp);
+  return msg;
+}
+
+
+void luaO_chunkid (char *out, const char *source, size_t bufflen) {
+  if (*source == '=') {
+    strncpy(out, source+1, bufflen);  /* remove first char */
+    out[bufflen-1] = '\0';  /* ensures null termination */
+  }
+  else {  /* out = "source", or "...source" */
+    if (*source == '@') {
+      size_t l;
+      source++;  /* skip the `@' */
+      bufflen -= sizeof(" '...' ");
+      l = strlen(source);
+      strcpy(out, "");
+      if (l > bufflen) {
+        source += (l-bufflen);  /* get last part of file name */
+        strcat(out, "...");
+      }
+      strcat(out, source);
+    }
+    else {  /* out = [string "string"] */
+      size_t len = strcspn(source, "\n\r");  /* stop at first newline */
+      bufflen -= sizeof(" [string \"...\"] ");
+      if (len > bufflen) len = bufflen;
+      strcpy(out, "[string \"");
+      if (source[len] != '\0') {  /* must truncate? */
+        strncat(out, source, len);
+        strcat(out, "...");
+      }
+      else
+        strcat(out, source);
+      strcat(out, "\"]");
+    }
+  }
+}

=== added file 'lua/lobject.h'
--- lua/lobject.h	1970-01-01 00:00:00 +0000
+++ lua/lobject.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,383 @@
+/*
+** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
+** Type definitions for Lua objects
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lobject_h
+#define lobject_h
+
+
+#ifndef USE_GRUB_LIB
+#include <stdarg.h>
+#endif /* ! USE_GRUB_LIB */
+
+
+#include "llimits.h"
+#include "lua.h"
+
+
+/* tags for values visible from Lua */
+#define LAST_TAG	LUA_TTHREAD
+
+#define NUM_TAGS	(LAST_TAG+1)
+
+
+/*
+** Extra tags for non-values
+*/
+#define LUA_TPROTO	(LAST_TAG+1)
+#define LUA_TUPVAL	(LAST_TAG+2)
+#define LUA_TDEADKEY	(LAST_TAG+3)
+
+
+/*
+** Union of all collectable objects
+*/
+typedef union GCObject GCObject;
+
+
+/*
+** Common Header for all collectable objects (in macro form, to be
+** included in other objects)
+*/
+#define CommonHeader	GCObject *next; lu_byte tt; lu_byte marked
+
+
+/*
+** Common header in struct form
+*/
+typedef struct GCheader {
+  CommonHeader;
+} GCheader;
+
+
+
+
+/*
+** Union of all Lua values
+*/
+typedef union {
+  GCObject *gc;
+  void *p;
+  lua_Number n;
+  int b;
+} Value;
+
+
+/*
+** Tagged Values
+*/
+
+#define TValuefields	Value value; int tt
+
+typedef struct lua_TValue {
+  TValuefields;
+} TValue;
+
+
+/* Macros to test type */
+#define ttisnil(o)	(ttype(o) == LUA_TNIL)
+#define ttisnumber(o)	(ttype(o) == LUA_TNUMBER)
+#define ttisstring(o)	(ttype(o) == LUA_TSTRING)
+#define ttistable(o)	(ttype(o) == LUA_TTABLE)
+#define ttisfunction(o)	(ttype(o) == LUA_TFUNCTION)
+#define ttisboolean(o)	(ttype(o) == LUA_TBOOLEAN)
+#define ttisuserdata(o)	(ttype(o) == LUA_TUSERDATA)
+#define ttisthread(o)	(ttype(o) == LUA_TTHREAD)
+#define ttislightuserdata(o)	(ttype(o) == LUA_TLIGHTUSERDATA)
+
+/* Macros to access values */
+#define ttype(o)	((o)->tt)
+#define gcvalue(o)	check_exp(iscollectable(o), (o)->value.gc)
+#define pvalue(o)	check_exp(ttislightuserdata(o), (o)->value.p)
+#define nvalue(o)	check_exp(ttisnumber(o), (o)->value.n)
+#define rawtsvalue(o)	check_exp(ttisstring(o), &(o)->value.gc->ts)
+#define tsvalue(o)	(&rawtsvalue(o)->tsv)
+#define rawuvalue(o)	check_exp(ttisuserdata(o), &(o)->value.gc->u)
+#define uvalue(o)	(&rawuvalue(o)->uv)
+#define clvalue(o)	check_exp(ttisfunction(o), &(o)->value.gc->cl)
+#define hvalue(o)	check_exp(ttistable(o), &(o)->value.gc->h)
+#define bvalue(o)	check_exp(ttisboolean(o), (o)->value.b)
+#define thvalue(o)	check_exp(ttisthread(o), &(o)->value.gc->th)
+
+#define l_isfalse(o)	(ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
+
+/*
+** for internal debug only
+*/
+#define checkconsistency(obj) \
+  lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
+
+#define checkliveness(g,obj) \
+  lua_assert(!iscollectable(obj) || \
+  ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc)))
+
+
+/* Macros to set values */
+#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
+
+#define setnvalue(obj,x) \
+  { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; }
+
+#define setpvalue(obj,x) \
+  { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; }
+
+#define setbvalue(obj,x) \
+  { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; }
+
+#define setsvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \
+    checkliveness(G(L),i_o); }
+
+#define setuvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \
+    checkliveness(G(L),i_o); }
+
+#define setthvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \
+    checkliveness(G(L),i_o); }
+
+#define setclvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \
+    checkliveness(G(L),i_o); }
+
+#define sethvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \
+    checkliveness(G(L),i_o); }
+
+#define setptvalue(L,obj,x) \
+  { TValue *i_o=(obj); \
+    i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \
+    checkliveness(G(L),i_o); }
+
+
+
+
+#define setobj(L,obj1,obj2) \
+  { const TValue *o2=(obj2); TValue *o1=(obj1); \
+    o1->value = o2->value; o1->tt=o2->tt; \
+    checkliveness(G(L),o1); }
+
+
+/*
+** different types of sets, according to destination
+*/
+
+/* from stack to (same) stack */
+#define setobjs2s	setobj
+/* to stack (not from same stack) */
+#define setobj2s	setobj
+#define setsvalue2s	setsvalue
+#define sethvalue2s	sethvalue
+#define setptvalue2s	setptvalue
+/* from table to same table */
+#define setobjt2t	setobj
+/* to table */
+#define setobj2t	setobj
+/* to new object */
+#define setobj2n	setobj
+#define setsvalue2n	setsvalue
+
+#define setttype(obj, tt) (ttype(obj) = (tt))
+
+
+#define iscollectable(o)	(ttype(o) >= LUA_TSTRING)
+
+
+
+typedef TValue *StkId;  /* index to stack elements */
+
+
+/*
+** String headers for string table
+*/
+typedef union TString {
+  L_Umaxalign dummy;  /* ensures maximum alignment for strings */
+  struct {
+    CommonHeader;
+    lu_byte reserved;
+    unsigned int hash;
+    size_t len;
+  } tsv;
+} TString;
+
+
+#define getstr(ts)	cast(const char *, (ts) + 1)
+#define svalue(o)       getstr(tsvalue(o))
+
+
+
+typedef union Udata {
+  L_Umaxalign dummy;  /* ensures maximum alignment for `local' udata */
+  struct {
+    CommonHeader;
+    struct Table *metatable;
+    struct Table *env;
+    size_t len;
+  } uv;
+} Udata;
+
+
+
+
+/*
+** Function Prototypes
+*/
+typedef struct Proto {
+  CommonHeader;
+  TValue *k;  /* constants used by the function */
+  Instruction *code;
+  struct Proto **p;  /* functions defined inside the function */
+  int *lineinfo;  /* map from opcodes to source lines */
+  struct LocVar *locvars;  /* information about local variables */
+  TString **upvalues;  /* upvalue names */
+  TString  *source;
+  int sizeupvalues;
+  int sizek;  /* size of `k' */
+  int sizecode;
+  int sizelineinfo;
+  int sizep;  /* size of `p' */
+  int sizelocvars;
+  int linedefined;
+  int lastlinedefined;
+  GCObject *gclist;
+  lu_byte nups;  /* number of upvalues */
+  lu_byte numparams;
+  lu_byte is_vararg;
+  lu_byte maxstacksize;
+} Proto;
+
+
+/* masks for new-style vararg */
+#define VARARG_HASARG		1
+#define VARARG_ISVARARG		2
+#define VARARG_NEEDSARG		4
+
+
+typedef struct LocVar {
+  TString *varname;
+  int startpc;  /* first point where variable is active */
+  int endpc;    /* first point where variable is dead */
+} LocVar;
+
+
+
+/*
+** Upvalues
+*/
+
+typedef struct UpVal {
+  CommonHeader;
+  TValue *v;  /* points to stack or to its own value */
+  union {
+    TValue value;  /* the value (when closed) */
+    struct {  /* double linked list (when open) */
+      struct UpVal *prev;
+      struct UpVal *next;
+    } l;
+  } u;
+} UpVal;
+
+
+/*
+** Closures
+*/
+
+#define ClosureHeader \
+	CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
+	struct Table *env
+
+typedef struct CClosure {
+  ClosureHeader;
+  lua_CFunction f;
+  TValue upvalue[1];
+} CClosure;
+
+
+typedef struct LClosure {
+  ClosureHeader;
+  struct Proto *p;
+  UpVal *upvals[1];
+} LClosure;
+
+
+typedef union Closure {
+  CClosure c;
+  LClosure l;
+} Closure;
+
+
+#define iscfunction(o)	(ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC)
+#define isLfunction(o)	(ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC)
+
+
+/*
+** Tables
+*/
+
+typedef union TKey {
+  struct {
+    TValuefields;
+    struct Node *next;  /* for chaining */
+  } nk;
+  TValue tvk;
+} TKey;
+
+
+typedef struct Node {
+  TValue i_val;
+  TKey i_key;
+} Node;
+
+
+typedef struct Table {
+  CommonHeader;
+  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */ 
+  lu_byte lsizenode;  /* log2 of size of `node' array */
+  struct Table *metatable;
+  TValue *array;  /* array part */
+  Node *node;
+  Node *lastfree;  /* any free position is before this position */
+  GCObject *gclist;
+  int sizearray;  /* size of `array' array */
+} Table;
+
+
+
+/*
+** `module' operation for hashing (size is always a power of 2)
+*/
+#define lmod(s,size) \
+	(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
+
+
+#define twoto(x)	(1<<(x))
+#define sizenode(t)	(twoto((t)->lsizenode))
+
+
+#define luaO_nilobject		(&luaO_nilobject_)
+
+LUAI_DATA const TValue luaO_nilobject_;
+
+#define ceillog2(x)	(luaO_log2((x)-1) + 1)
+
+LUAI_FUNC int luaO_log2 (unsigned int x);
+LUAI_FUNC int luaO_int2fb (unsigned int x);
+LUAI_FUNC int luaO_fb2int (int x);
+LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2);
+LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result);
+LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
+                                                       va_list argp);
+LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
+LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
+
+
+#endif
+

=== added file 'lua/lopcodes.c'
--- lua/lopcodes.c	1970-01-01 00:00:00 +0000
+++ lua/lopcodes.c	2008-08-01 15:19:23 +0000
@@ -0,0 +1,102 @@
+/*
+** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
+** See Copyright Notice in lua.h
+*/
+
+
+#define lopcodes_c
+#define LUA_CORE
+
+
+#include "lopcodes.h"
+
+
+/* ORDER OP */
+
+const char *const luaP_opnames[NUM_OPCODES+1] = {
+  "MOVE",
+  "LOADK",
+  "LOADBOOL",
+  "LOADNIL",
+  "GETUPVAL",
+  "GETGLOBAL",
+  "GETTABLE",
+  "SETGLOBAL",
+  "SETUPVAL",
+  "SETTABLE",
+  "NEWTABLE",
+  "SELF",
+  "ADD",
+  "SUB",
+  "MUL",
+  "DIV",
+  "MOD",
+  "POW",
+  "UNM",
+  "NOT",
+  "LEN",
+  "CONCAT",
+  "JMP",
+  "EQ",
+  "LT",
+  "LE",
+  "TEST",
+  "TESTSET",
+  "CALL",
+  "TAILCALL",
+  "RETURN",
+  "FORLOOP",
+  "FORPREP",
+  "TFORLOOP",
+  "SETLIST",
+  "CLOSE",
+  "CLOSURE",
+  "VARARG",
+  NULL
+};
+
+
+#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
+
+const lu_byte luaP_opmodes[NUM_OPCODES] = {
+/*       T  A    B       C     mode		   opcode	*/
+  opmode(0, 1, OpArgR, OpArgN, iABC) 		/* OP_MOVE */
+ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LOADNIL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
+ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_GETGLOBAL */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 0, OpArgK, OpArgN, iABx)		/* OP_SETGLOBAL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
+ ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
+ ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
+ ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TFORLOOP */
+ ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
+ ,opmode(0, 0, OpArgN, OpArgN, iABC)		/* OP_CLOSE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
+};
+

=== added file 'lua/lopcodes.h'
--- lua/lopcodes.h	1970-01-01 00:00:00 +0000
+++ lua/lopcodes.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,268 @@
+/*
+** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $
+** Opcodes for Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lopcodes_h
+#define lopcodes_h
+
+#include "llimits.h"
+
+
+/*===========================================================================
+  We assume that instructions are unsigned numbers.
+  All instructions have an opcode in the first 6 bits.
+  Instructions can have the following fields:
+	`A' : 8 bits
+	`B' : 9 bits
+	`C' : 9 bits
+	`Bx' : 18 bits (`B' and `C' together)
+	`sBx' : signed Bx
+
+  A signed argument is represented in excess K; that is, the number
+  value is the unsigned value minus K. K is exactly the maximum value
+  for that argument (so that -max is represented by 0, and +max is
+  represented by 2*max), which is half the maximum for the corresponding
+  unsigned argument.
+===========================================================================*/
+
+
+enum OpMode {iABC, iABx, iAsBx};  /* basic instruction format */
+
+
+/*
+** size and position of opcode arguments.
+*/
+#define SIZE_C		9
+#define SIZE_B		9
+#define SIZE_Bx		(SIZE_C + SIZE_B)
+#define SIZE_A		8
+
+#define SIZE_OP		6
+
+#define POS_OP		0
+#define POS_A		(POS_OP + SIZE_OP)
+#define POS_C		(POS_A + SIZE_A)
+#define POS_B		(POS_C + SIZE_C)
+#define POS_Bx		POS_C
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
+*/
+#if SIZE_Bx < LUAI_BITSINT-1
+#define MAXARG_Bx        ((1<<SIZE_Bx)-1)
+#define MAXARG_sBx        (MAXARG_Bx>>1)         /* `sBx' is signed */
+#else
+#define MAXARG_Bx        MAX_INT
+#define MAXARG_sBx        MAX_INT
+#endif
+
+
+#define MAXARG_A        ((1<<SIZE_A)-1)
+#define MAXARG_B        ((1<<SIZE_B)-1)
+#define MAXARG_C        ((1<<SIZE_C)-1)
+
+
+/* creates a mask with `n' 1 bits at position `p' */
+#define MASK1(n,p)	((~((~(Instruction)0)<<n))<<p)
+
+/* creates a mask with `n' 0 bits at position `p' */
+#define MASK0(n,p)	(~MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define GET_OPCODE(i)	(cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
+#define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
+		((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
+
+#define GETARG_A(i)	(cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0)))
+#define SETARG_A(i,u)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
+		((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A))))
+
+#define GETARG_B(i)	(cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0)))
+#define SETARG_B(i,b)	((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
+		((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B))))
+
+#define GETARG_C(i)	(cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0)))
+#define SETARG_C(i,b)	((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
+		((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C))))
+
+#define GETARG_Bx(i)	(cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0)))
+#define SETARG_Bx(i,b)	((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \
+		((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx))))
+
+#define GETARG_sBx(i)	(GETARG_Bx(i)-MAXARG_sBx)
+#define SETARG_sBx(i,b)	SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
+
+
+#define CREATE_ABC(o,a,b,c)	((cast(Instruction, o)<<POS_OP) \
+			| (cast(Instruction, a)<<POS_A) \
+			| (cast(Instruction, b)<<POS_B) \
+			| (cast(Instruction, c)<<POS_C))
+
+#define CREATE_ABx(o,a,bc)	((cast(Instruction, o)<<POS_OP) \
+			| (cast(Instruction, a)<<POS_A) \
+			| (cast(Instruction, bc)<<POS_Bx))
+
+
+/*
+** Macros to operate RK indices
+*/
+
+/* this bit 1 means constant (0 means register) */
+#define BITRK		(1 << (SIZE_B - 1))
+
+/* test whether value is a constant */
+#define ISK(x)		((x) & BITRK)
+
+/* gets the index of the constant */
+#define INDEXK(r)	((int)(r) & ~BITRK)
+
+#define MAXINDEXRK	(BITRK - 1)
+
+/* code a constant index as a RK value */
+#define RKASK(x)	((x) | BITRK)
+
+
+/*
+** invalid register that fits in 8 bits
+*/
+#define NO_REG		MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
+*/
+
+
+/*
+** grep "ORDER OP" if you change these enums
+*/
+
+typedef enum {
+/*----------------------------------------------------------------------
+name		args	description
+------------------------------------------------------------------------*/
+OP_MOVE,/*	A B	R(A) := R(B)					*/
+OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
+OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
+OP_LOADNIL,/*	A B	R(A) := ... := R(B) := nil			*/
+OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
+
+OP_GETGLOBAL,/*	A Bx	R(A) := Gbl[Kst(Bx)]				*/
+OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
+
+OP_SETGLOBAL,/*	A Bx	Gbl[Kst(Bx)] := R(A)				*/
+OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
+OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
+
+OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
+
+OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
+
+OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
+OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
+OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
+OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
+OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
+OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
+OP_UNM,/*	A B	R(A) := -R(B)					*/
+OP_NOT,/*	A B	R(A) := not R(B)				*/
+OP_LEN,/*	A B	R(A) := length of R(B)				*/
+
+OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
+
+OP_JMP,/*	sBx	pc+=sBx					*/
+
+OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
+OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++  		*/
+OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++  		*/
+
+OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/ 
+OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/ 
+
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
+OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
+OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
+
+OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
+			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
+OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
+
+OP_TFORLOOP,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); 
+                        if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++	*/ 
+OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
+
+OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
+OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))	*/
+
+OP_VARARG/*	A B	R(A), R(A+1), ..., R(A+B-1) = vararg		*/
+} OpCode;
+
+
+#define NUM_OPCODES	(cast(int, OP_VARARG) + 1)
+
+
+
+/*===========================================================================
+  Notes:
+  (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
+      and can be 0: OP_CALL then sets `top' to last_result+1, so
+      next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
+
+  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
+      set top (like in OP_CALL with C == 0).
+
+  (*) In OP_RETURN, if (B == 0) then return up to `top'
+
+  (*) In OP_SETLIST, if (B == 0) then B = `top';
+      if (C == 0) then next `instruction' is real C
+
+  (*) For comparisons, A specifies what condition the test should accept
+      (true or false).
+
+  (*) All `skips' (pc++) assume that next instruction is a jump
+===========================================================================*/
+
+
+/*
+** masks for instruction properties. The format is:
+** bits 0-1: op mode
+** bits 2-3: C arg mode
+** bits 4-5: B arg mode
+** bit 6: instruction set register A
+** bit 7: operator is a test
+*/  
+
+enum OpArgMask {
+  OpArgN,  /* argument is not used */
+  OpArgU,  /* argument is used */
+  OpArgR,  /* argument is a register or a jump offset */
+  OpArgK   /* argument is a constant or register/constant */
+};
+
+LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES];
+
+#define getOpMode(m)	(cast(enum OpMode, luaP_opmodes[m] & 3))
+#define getBMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
+#define getCMode(m)	(cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
+#define testAMode(m)	(luaP_opmodes[m] & (1 << 6))
+#define testTMode(m)	(luaP_opmodes[m] & (1 << 7))
+
+
+LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1];  /* opcode names */
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define LFIELDS_PER_FLUSH	50
+
+
+#endif

=== added file 'lua/loslib.c'
--- lua/loslib.c	1970-01-01 00:00:00 +0000
+++ lua/loslib.c	2008-08-01 15:21:04 +0000
@@ -0,0 +1,247 @@
+/*
+** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $
+** Standard Operating System library
+** See Copyright Notice in lua.h
+*/
+
+
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define loslib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+static int os_pushresult (lua_State *L, int i, const char *filename) {
+  int en = errno;  /* calls to Lua API may change this value */
+  if (i) {
+    lua_pushboolean(L, 1);
+    return 1;
+  }
+  else {
+    lua_pushnil(L);
+    lua_pushfstring(L, "%s: %s", filename, strerror(en));
+    lua_pushinteger(L, en);
+    return 3;
+  }
+}
+
+
+static int os_execute (lua_State *L) {
+  lua_pushinteger(L, system(luaL_optstring(L, 1, NULL)));
+  return 1;
+}
+
+
+static int os_remove (lua_State *L) {
+  const char *filename = luaL_checkstring(L, 1);
+  return os_pushresult(L, remove(filename) == 0, filename);
+}
+
+
+static int os_rename (lua_State *L) {
+  const char *fromname = luaL_checkstring(L, 1);
+  const char *toname = luaL_checkstring(L, 2);
+  return os_pushresult(L, rename(fromname, toname) == 0, fromname);
+}
+
+
+static int os_tmpname (lua_State *L) {
+  char buff[LUA_TMPNAMBUFSIZE];
+  int err;
+  lua_tmpnam(buff, err);
+  if (err)
+    return luaL_error(L, "unable to generate a unique filename");
+  lua_pushstring(L, buff);
+  return 1;
+}
+
+
+static int os_getenv (lua_State *L) {
+  lua_pushstring(L, getenv(luaL_checkstring(L, 1)));  /* if NULL push nil */
+  return 1;
+}
+
+
+static int os_clock (lua_State *L) {
+  lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC);
+  return 1;
+}
+
+
+/*
+** {======================================================
+** Time/Date operations
+** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S,
+**   wday=%w+1, yday=%j, isdst=? }
+** =======================================================
+*/
+
+static void setfield (lua_State *L, const char *key, int value) {
+  lua_pushinteger(L, value);
+  lua_setfield(L, -2, key);
+}
+
+static void setboolfield (lua_State *L, const char *key, int value) {
+  if (value < 0)  /* undefined? */
+    return;  /* does not set field */
+  lua_pushboolean(L, value);
+  lua_setfield(L, -2, key);
+}
+
+static int getboolfield (lua_State *L, const char *key) {
+  int res;
+  lua_getfield(L, -1, key);
+  res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
+  lua_pop(L, 1);
+  return res;
+}
+
+
+static int getfield (lua_State *L, const char *key, int d) {
+  int res;
+  lua_getfield(L, -1, key);
+  if (lua_isnumber(L, -1))
+    res = (int)lua_tointeger(L, -1);
+  else {
+    if (d < 0)
+      return luaL_error(L, "field " LUA_QS " missing in date table", key);
+    res = d;
+  }
+  lua_pop(L, 1);
+  return res;
+}
+
+
+static int os_date (lua_State *L) {
+  const char *s = luaL_optstring(L, 1, "%c");
+  time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
+  struct tm *stm;
+  if (*s == '!') {  /* UTC? */
+    stm = gmtime(&t);
+    s++;  /* skip `!' */
+  }
+  else
+    stm = localtime(&t);
+  if (stm == NULL)  /* invalid date? */
+    lua_pushnil(L);
+  else if (strcmp(s, "*t") == 0) {
+    lua_createtable(L, 0, 9);  /* 9 = number of fields */
+    setfield(L, "sec", stm->tm_sec);
+    setfield(L, "min", stm->tm_min);
+    setfield(L, "hour", stm->tm_hour);
+    setfield(L, "day", stm->tm_mday);
+    setfield(L, "month", stm->tm_mon+1);
+    setfield(L, "year", stm->tm_year+1900);
+    setfield(L, "wday", stm->tm_wday+1);
+    setfield(L, "yday", stm->tm_yday+1);
+    setboolfield(L, "isdst", stm->tm_isdst);
+  }
+  else {
+    char cc[3];
+    luaL_Buffer b;
+    cc[0] = '%'; cc[2] = '\0';
+    luaL_buffinit(L, &b);
+    for (; *s; s++) {
+      if (*s != '%' || *(s + 1) == '\0')  /* no conversion specifier? */
+        luaL_addchar(&b, *s);
+      else {
+        size_t reslen;
+        char buff[200];  /* should be big enough for any conversion result */
+        cc[1] = *(++s);
+        reslen = strftime(buff, sizeof(buff), cc, stm);
+        luaL_addlstring(&b, buff, reslen);
+      }
+    }
+    luaL_pushresult(&b);
+  }
+  return 1;
+}
+
+
+static int os_time (lua_State *L) {
+  time_t t;
+  if (lua_isnoneornil(L, 1))  /* called without args? */
+    t = time(NULL);  /* get current time */
+  else {
+    struct tm ts;
+    luaL_checktype(L, 1, LUA_TTABLE);
+    lua_settop(L, 1);  /* make sure table is at the top */
+    ts.tm_sec = getfield(L, "sec", 0);
+    ts.tm_min = getfield(L, "min", 0);
+    ts.tm_hour = getfield(L, "hour", 12);
+    ts.tm_mday = getfield(L, "day", -1);
+    ts.tm_mon = getfield(L, "month", -1) - 1;
+    ts.tm_year = getfield(L, "year", -1) - 1900;
+    ts.tm_isdst = getboolfield(L, "isdst");
+    t = mktime(&ts);
+  }
+  if (t == (time_t)(-1))
+    lua_pushnil(L);
+  else
+    lua_pushnumber(L, (lua_Number)t);
+  return 1;
+}
+
+
+#if !defined LUA_NUMBER_INTEGRAL
+static int os_difftime (lua_State *L) {
+  lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
+                             (time_t)(luaL_optnumber(L, 2, 0))));
+  return 1;
+}
+#endif
+
+/* }====================================================== */
+
+
+static int os_setlocale (lua_State *L) {
+  static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY,
+                      LC_NUMERIC, LC_TIME};
+  static const char *const catnames[] = {"all", "collate", "ctype", "monetary",
+     "numeric", "time", NULL};
+  const char *l = luaL_optstring(L, 1, NULL);
+  int op = luaL_checkoption(L, 2, "all", catnames);
+  lua_pushstring(L, setlocale(cat[op], l));
+  return 1;
+}
+
+
+static int os_exit (lua_State *L) {
+  exit(luaL_optint(L, 1, EXIT_SUCCESS));
+}
+
+static const luaL_Reg syslib[] = {
+  {"clock",     os_clock},
+  {"date",      os_date},
+#if !defined LUA_NUMBER_INTEGRAL
+  {"difftime",  os_difftime},
+#endif
+  {"execute",   os_execute},
+  {"exit",      os_exit},
+  {"getenv",    os_getenv},
+  {"remove",    os_remove},
+  {"rename",    os_rename},
+  {"setlocale", os_setlocale},
+  {"time",      os_time},
+  {"tmpname",   os_tmpname},
+  {NULL, NULL}
+};
+
+/* }====================================================== */
+
+
+
+LUALIB_API int luaopen_os (lua_State *L) {
+  luaL_register(L, LUA_OSLIBNAME, syslib);
+  return 1;
+}
+

=== added file 'lua/lparser.c'
--- lua/lparser.c	1970-01-01 00:00:00 +0000
+++ lua/lparser.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,1341 @@
+/*
+** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lparser_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lparser.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+
+
+
+#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
+
+#define getlocvar(fs, i)	((fs)->f->locvars[(fs)->actvar[i]])
+
+#define luaY_checklimit(fs,v,l,m)	if ((v)>(l)) errorlimit(fs,l,m)
+
+
+/*
+** nodes for block list (list of active blocks)
+*/
+typedef struct BlockCnt {
+  struct BlockCnt *previous;  /* chain */
+  int breaklist;  /* list of jumps out of this loop */
+  lu_byte nactvar;  /* # active locals outside the breakable structure */
+  lu_byte upval;  /* true if some variable in the block is an upvalue */
+  lu_byte isbreakable;  /* true if `block' is a loop */
+} BlockCnt;
+
+
+
+/*
+** prototypes for recursive non-terminal functions
+*/
+static void chunk (LexState *ls);
+static void expr (LexState *ls, expdesc *v);
+
+
+static void anchor_token (LexState *ls) {
+  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
+    TString *ts = ls->t.seminfo.ts;
+    luaX_newstring(ls, getstr(ts), ts->tsv.len);
+  }
+}
+
+
+static void error_expected (LexState *ls, int token) {
+  luaX_syntaxerror(ls,
+      luaO_pushfstring(ls->L, LUA_QS " expected", luaX_token2str(ls, token)));
+}
+
+
+static void errorlimit (FuncState *fs, int limit, const char *what) {
+  const char *msg = (fs->f->linedefined == 0) ?
+    luaO_pushfstring(fs->L, "main function has more than %d %s", limit, what) :
+    luaO_pushfstring(fs->L, "function at line %d has more than %d %s",
+                            fs->f->linedefined, limit, what);
+  luaX_lexerror(fs->ls, msg, 0);
+}
+
+
+static int testnext (LexState *ls, int c) {
+  if (ls->t.token == c) {
+    luaX_next(ls);
+    return 1;
+  }
+  else return 0;
+}
+
+
+static void check (LexState *ls, int c) {
+  if (ls->t.token != c)
+    error_expected(ls, c);
+}
+
+static void checknext (LexState *ls, int c) {
+  check(ls, c);
+  luaX_next(ls);
+}
+
+
+#define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }
+
+
+
+static void check_match (LexState *ls, int what, int who, int where) {
+  if (!testnext(ls, what)) {
+    if (where == ls->linenumber)
+      error_expected(ls, what);
+    else {
+      luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
+             LUA_QS " expected (to close " LUA_QS " at line %d)",
+              luaX_token2str(ls, what), luaX_token2str(ls, who), where));
+    }
+  }
+}
+
+
+static TString *str_checkname (LexState *ls) {
+  TString *ts;
+  check(ls, TK_NAME);
+  ts = ls->t.seminfo.ts;
+  luaX_next(ls);
+  return ts;
+}
+
+
+static void init_exp (expdesc *e, expkind k, int i) {
+  e->f = e->t = NO_JUMP;
+  e->k = k;
+  e->u.s.info = i;
+}
+
+
+static void codestring (LexState *ls, expdesc *e, TString *s) {
+  init_exp(e, VK, luaK_stringK(ls->fs, s));
+}
+
+
+static void checkname(LexState *ls, expdesc *e) {
+  codestring(ls, e, str_checkname(ls));
+}
+
+
+static int registerlocalvar (LexState *ls, TString *varname) {
+  FuncState *fs = ls->fs;
+  Proto *f = fs->f;
+  int oldsize = f->sizelocvars;
+  luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
+                  LocVar, SHRT_MAX, "too many local variables");
+  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
+  f->locvars[fs->nlocvars].varname = varname;
+  luaC_objbarrier(ls->L, f, varname);
+  return fs->nlocvars++;
+}
+
+
+#define new_localvarliteral(ls,v,n) \
+  new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char))-1), n)
+
+
+static void new_localvar (LexState *ls, TString *name, int n) {
+  FuncState *fs = ls->fs;
+  luaY_checklimit(fs, fs->nactvar+n+1, LUAI_MAXVARS, "local variables");
+  fs->actvar[fs->nactvar+n] = cast(unsigned short, registerlocalvar(ls, name));
+}
+
+
+static void adjustlocalvars (LexState *ls, int nvars) {
+  FuncState *fs = ls->fs;
+  fs->nactvar = cast_byte(fs->nactvar + nvars);
+  for (; nvars; nvars--) {
+    getlocvar(fs, fs->nactvar - nvars).startpc = fs->pc;
+  }
+}
+
+
+static void removevars (LexState *ls, int tolevel) {
+  FuncState *fs = ls->fs;
+  while (fs->nactvar > tolevel)
+    getlocvar(fs, --fs->nactvar).endpc = fs->pc;
+}
+
+
+static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
+  int i;
+  Proto *f = fs->f;
+  int oldsize = f->sizeupvalues;
+  for (i=0; i<f->nups; i++) {
+    if (fs->upvalues[i].k == v->k && fs->upvalues[i].info == v->u.s.info) {
+      lua_assert(f->upvalues[i] == name);
+      return i;
+    }
+  }
+  /* new one */
+  luaY_checklimit(fs, f->nups + 1, LUAI_MAXUPVALUES, "upvalues");
+  luaM_growvector(fs->L, f->upvalues, f->nups, f->sizeupvalues,
+                  TString *, MAX_INT, "");
+  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++] = NULL;
+  f->upvalues[f->nups] = name;
+  luaC_objbarrier(fs->L, f, name);
+  lua_assert(v->k == VLOCAL || v->k == VUPVAL);
+  fs->upvalues[f->nups].k = cast_byte(v->k);
+  fs->upvalues[f->nups].info = cast_byte(v->u.s.info);
+  return f->nups++;
+}
+
+
+static int searchvar (FuncState *fs, TString *n) {
+  int i;
+  for (i=fs->nactvar-1; i >= 0; i--) {
+    if (n == getlocvar(fs, i).varname)
+      return i;
+  }
+  return -1;  /* not found */
+}
+
+
+static void markupval (FuncState *fs, int level) {
+  BlockCnt *bl = fs->bl;
+  while (bl && bl->nactvar > level) bl = bl->previous;
+  if (bl) bl->upval = 1;
+}
+
+
+static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+  if (fs == NULL) {  /* no more levels? */
+    init_exp(var, VGLOBAL, NO_REG);  /* default is global variable */
+    return VGLOBAL;
+  }
+  else {
+    int v = searchvar(fs, n);  /* look up at current level */
+    if (v >= 0) {
+      init_exp(var, VLOCAL, v);
+      if (!base)
+        markupval(fs, v);  /* local will be used as an upval */
+      return VLOCAL;
+    }
+    else {  /* not found at current level; try upper one */
+      if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
+        return VGLOBAL;
+      var->u.s.info = indexupvalue(fs, n, var);  /* else was LOCAL or UPVAL */
+      var->k = VUPVAL;  /* upvalue in this level */
+      return VUPVAL;
+    }
+  }
+}
+
+
+static void singlevar (LexState *ls, expdesc *var) {
+  TString *varname = str_checkname(ls);
+  FuncState *fs = ls->fs;
+  if (singlevaraux(fs, varname, var, 1) == VGLOBAL)
+    var->u.s.info = luaK_stringK(fs, varname);  /* info points to global name */
+}
+
+
+static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
+  FuncState *fs = ls->fs;
+  int extra = nvars - nexps;
+  if (hasmultret(e->k)) {
+    extra++;  /* includes call itself */
+    if (extra < 0) extra = 0;
+    luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
+    if (extra > 1) luaK_reserveregs(fs, extra-1);
+  }
+  else {
+    if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
+    if (extra > 0) {
+      int reg = fs->freereg;
+      luaK_reserveregs(fs, extra);
+      luaK_nil(fs, reg, extra);
+    }
+  }
+}
+
+
+static void enterlevel (LexState *ls) {
+  if (++ls->L->nCcalls > LUAI_MAXCCALLS)
+	luaX_lexerror(ls, "chunk has too many syntax levels", 0);
+}
+
+
+#define leavelevel(ls)	((ls)->L->nCcalls--)
+
+
+static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isbreakable) {
+  bl->breaklist = NO_JUMP;
+  bl->isbreakable = isbreakable;
+  bl->nactvar = fs->nactvar;
+  bl->upval = 0;
+  bl->previous = fs->bl;
+  fs->bl = bl;
+  lua_assert(fs->freereg == fs->nactvar);
+}
+
+
+static void leaveblock (FuncState *fs) {
+  BlockCnt *bl = fs->bl;
+  fs->bl = bl->previous;
+  removevars(fs->ls, bl->nactvar);
+  if (bl->upval)
+    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
+  /* a block either controls scope or breaks (never both) */
+  lua_assert(!bl->isbreakable || !bl->upval);
+  lua_assert(bl->nactvar == fs->nactvar);
+  fs->freereg = fs->nactvar;  /* free registers */
+  luaK_patchtohere(fs, bl->breaklist);
+}
+
+
+static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
+  FuncState *fs = ls->fs;
+  Proto *f = fs->f;
+  int oldsize = f->sizep;
+  int i;
+  luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
+                  MAXARG_Bx, "constant table overflow");
+  while (oldsize < f->sizep) f->p[oldsize++] = NULL;
+  f->p[fs->np++] = func->f;
+  luaC_objbarrier(ls->L, f, func->f);
+  init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
+  for (i=0; i<func->f->nups; i++) {
+    OpCode o = (func->upvalues[i].k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
+    luaK_codeABC(fs, o, 0, func->upvalues[i].info, 0);
+  }
+}
+
+
+static void open_func (LexState *ls, FuncState *fs) {
+  lua_State *L = ls->L;
+  Proto *f = luaF_newproto(L);
+  fs->f = f;
+  fs->prev = ls->fs;  /* linked list of funcstates */
+  fs->ls = ls;
+  fs->L = L;
+  ls->fs = fs;
+  fs->pc = 0;
+  fs->lasttarget = -1;
+  fs->jpc = NO_JUMP;
+  fs->freereg = 0;
+  fs->nk = 0;
+  fs->np = 0;
+  fs->nlocvars = 0;
+  fs->nactvar = 0;
+  fs->bl = NULL;
+  f->source = ls->source;
+  f->maxstacksize = 2;  /* registers 0/1 are always valid */
+  fs->h = luaH_new(L, 0, 0);
+  /* anchor table of constants and prototype (to avoid being collected) */
+  sethvalue2s(L, L->top, fs->h);
+  incr_top(L);
+  setptvalue2s(L, L->top, f);
+  incr_top(L);
+}
+
+
+static void close_func (LexState *ls) {
+  lua_State *L = ls->L;
+  FuncState *fs = ls->fs;
+  Proto *f = fs->f;
+  removevars(ls, 0);
+  luaK_ret(fs, 0, 0);  /* final return */
+  luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
+  f->sizecode = fs->pc;
+  luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
+  f->sizelineinfo = fs->pc;
+  luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
+  f->sizek = fs->nk;
+  luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
+  f->sizep = fs->np;
+  luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
+  f->sizelocvars = fs->nlocvars;
+  luaM_reallocvector(L, f->upvalues, f->sizeupvalues, f->nups, TString *);
+  f->sizeupvalues = f->nups;
+  lua_assert(luaG_checkcode(f));
+  lua_assert(fs->bl == NULL);
+  ls->fs = fs->prev;
+  L->top -= 2;  /* remove table and prototype from the stack */
+  /* last token read was anchored in defunct function; must reanchor it */
+  if (fs) anchor_token(ls);
+}
+
+
+Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) {
+  struct LexState lexstate;
+  struct FuncState funcstate;
+  lexstate.buff = buff;
+  luaX_setinput(L, &lexstate, z, luaS_new(L, name));
+  open_func(&lexstate, &funcstate);
+  funcstate.f->is_vararg = VARARG_ISVARARG;  /* main func. is always vararg */
+  luaX_next(&lexstate);  /* read first token */
+  chunk(&lexstate);
+  check(&lexstate, TK_EOS);
+  close_func(&lexstate);
+  lua_assert(funcstate.prev == NULL);
+  lua_assert(funcstate.f->nups == 0);
+  lua_assert(lexstate.fs == NULL);
+  return funcstate.f;
+}
+
+
+
+/*============================================================*/
+/* GRAMMAR RULES */
+/*============================================================*/
+
+
+static void field (LexState *ls, expdesc *v) {
+  /* field -> ['.' | ':'] NAME */
+  FuncState *fs = ls->fs;
+  expdesc key;
+  luaK_exp2anyreg(fs, v);
+  luaX_next(ls);  /* skip the dot or colon */
+  checkname(ls, &key);
+  luaK_indexed(fs, v, &key);
+}
+
+
+static void yindex (LexState *ls, expdesc *v) {
+  /* index -> '[' expr ']' */
+  luaX_next(ls);  /* skip the '[' */
+  expr(ls, v);
+  luaK_exp2val(ls->fs, v);
+  checknext(ls, ']');
+}
+
+
+/*
+** {======================================================================
+** Rules for Constructors
+** =======================================================================
+*/
+
+
+struct ConsControl {
+  expdesc v;  /* last list item read */
+  expdesc *t;  /* table descriptor */
+  int nh;  /* total number of `record' elements */
+  int na;  /* total number of array elements */
+  int tostore;  /* number of array elements pending to be stored */
+};
+
+
+static void recfield (LexState *ls, struct ConsControl *cc) {
+  /* recfield -> (NAME | `['exp1`]') = exp1 */
+  FuncState *fs = ls->fs;
+  int reg = ls->fs->freereg;
+  expdesc key, val;
+  int rkkey;
+  if (ls->t.token == TK_NAME) {
+    luaY_checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
+    checkname(ls, &key);
+  }
+  else  /* ls->t.token == '[' */
+    yindex(ls, &key);
+  cc->nh++;
+  checknext(ls, '=');
+  rkkey = luaK_exp2RK(fs, &key);
+  expr(ls, &val);
+  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.s.info, rkkey, luaK_exp2RK(fs, &val));
+  fs->freereg = reg;  /* free registers */
+}
+
+
+static void closelistfield (FuncState *fs, struct ConsControl *cc) {
+  if (cc->v.k == VVOID) return;  /* there is no list item */
+  luaK_exp2nextreg(fs, &cc->v);
+  cc->v.k = VVOID;
+  if (cc->tostore == LFIELDS_PER_FLUSH) {
+    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);  /* flush */
+    cc->tostore = 0;  /* no more items pending */
+  }
+}
+
+
+static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
+  if (cc->tostore == 0) return;
+  if (hasmultret(cc->v.k)) {
+    luaK_setmultret(fs, &cc->v);
+    luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET);
+    cc->na--;  /* do not count last expression (unknown number of elements) */
+  }
+  else {
+    if (cc->v.k != VVOID)
+      luaK_exp2nextreg(fs, &cc->v);
+    luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore);
+  }
+}
+
+
+static void listfield (LexState *ls, struct ConsControl *cc) {
+  expr(ls, &cc->v);
+  luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
+  cc->na++;
+  cc->tostore++;
+}
+
+
+static void constructor (LexState *ls, expdesc *t) {
+  /* constructor -> ?? */
+  FuncState *fs = ls->fs;
+  int line = ls->linenumber;
+  int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
+  struct ConsControl cc;
+  cc.na = cc.nh = cc.tostore = 0;
+  cc.t = t;
+  init_exp(t, VRELOCABLE, pc);
+  init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
+  luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top (for gc) */
+  checknext(ls, '{');
+  do {
+    lua_assert(cc.v.k == VVOID || cc.tostore > 0);
+    if (ls->t.token == '}') break;
+    closelistfield(fs, &cc);
+    switch(ls->t.token) {
+      case TK_NAME: {  /* may be listfields or recfields */
+        luaX_lookahead(ls);
+        if (ls->lookahead.token != '=')  /* expression? */
+          listfield(ls, &cc);
+        else
+          recfield(ls, &cc);
+        break;
+      }
+      case '[': {  /* constructor_item -> recfield */
+        recfield(ls, &cc);
+        break;
+      }
+      default: {  /* constructor_part -> listfield */
+        listfield(ls, &cc);
+        break;
+      }
+    }
+  } while (testnext(ls, ',') || testnext(ls, ';'));
+  check_match(ls, '}', '{', line);
+  lastlistfield(fs, &cc);
+  SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
+  SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
+}
+
+/* }====================================================================== */
+
+
+
+static void parlist (LexState *ls) {
+  /* parlist -> [ param { `,' param } ] */
+  FuncState *fs = ls->fs;
+  Proto *f = fs->f;
+  int nparams = 0;
+  f->is_vararg = 0;
+  if (ls->t.token != ')') {  /* is `parlist' not empty? */
+    do {
+      switch (ls->t.token) {
+        case TK_NAME: {  /* param -> NAME */
+          new_localvar(ls, str_checkname(ls), nparams++);
+          break;
+        }
+        case TK_DOTS: {  /* param -> `...' */
+          luaX_next(ls);
+#if defined(LUA_COMPAT_VARARG)
+          /* use `arg' as default name */
+          new_localvarliteral(ls, "arg", nparams++);
+          f->is_vararg = VARARG_HASARG | VARARG_NEEDSARG;
+#endif
+          f->is_vararg |= VARARG_ISVARARG;
+          break;
+        }
+        default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
+      }
+    } while (!f->is_vararg && testnext(ls, ','));
+  }
+  adjustlocalvars(ls, nparams);
+  f->numparams = cast_byte(fs->nactvar - (f->is_vararg & VARARG_HASARG));
+  luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
+}
+
+
+static void body (LexState *ls, expdesc *e, int needself, int line) {
+  /* body ->  `(' parlist `)' chunk END */
+  FuncState new_fs;
+  open_func(ls, &new_fs);
+  new_fs.f->linedefined = line;
+  checknext(ls, '(');
+  if (needself) {
+    new_localvarliteral(ls, "self", 0);
+    adjustlocalvars(ls, 1);
+  }
+  parlist(ls);
+  checknext(ls, ')');
+  chunk(ls);
+  new_fs.f->lastlinedefined = ls->linenumber;
+  check_match(ls, TK_END, TK_FUNCTION, line);
+  close_func(ls);
+  pushclosure(ls, &new_fs, e);
+}
+
+
+static int explist1 (LexState *ls, expdesc *v) {
+  /* explist1 -> expr { `,' expr } */
+  int n = 1;  /* at least one expression */
+  expr(ls, v);
+  while (testnext(ls, ',')) {
+    luaK_exp2nextreg(ls->fs, v);
+    expr(ls, v);
+    n++;
+  }
+  return n;
+}
+
+
+static void funcargs (LexState *ls, expdesc *f) {
+  FuncState *fs = ls->fs;
+  expdesc args;
+  int base, nparams;
+  int line = ls->linenumber;
+  switch (ls->t.token) {
+    case '(': {  /* funcargs -> `(' [ explist1 ] `)' */
+      if (line != ls->lastline)
+        luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
+      luaX_next(ls);
+      if (ls->t.token == ')')  /* arg list is empty? */
+        args.k = VVOID;
+      else {
+        explist1(ls, &args);
+        luaK_setmultret(fs, &args);
+      }
+      check_match(ls, ')', '(', line);
+      break;
+    }
+    case '{': {  /* funcargs -> constructor */
+      constructor(ls, &args);
+      break;
+    }
+    case TK_STRING: {  /* funcargs -> STRING */
+      codestring(ls, &args, ls->t.seminfo.ts);
+      luaX_next(ls);  /* must use `seminfo' before `next' */
+      break;
+    }
+    default: {
+      luaX_syntaxerror(ls, "function arguments expected");
+      return;
+    }
+  }
+  lua_assert(f->k == VNONRELOC);
+  base = f->u.s.info;  /* base register for call */
+  if (hasmultret(args.k))
+    nparams = LUA_MULTRET;  /* open call */
+  else {
+    if (args.k != VVOID)
+      luaK_exp2nextreg(fs, &args);  /* close last argument */
+    nparams = fs->freereg - (base+1);
+  }
+  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
+  luaK_fixline(fs, line);
+  fs->freereg = base+1;  /* call remove function and arguments and leaves
+                            (unless changed) one result */
+}
+
+
+
+
+/*
+** {======================================================================
+** Expression parsing
+** =======================================================================
+*/
+
+
+static void prefixexp (LexState *ls, expdesc *v) {
+  /* prefixexp -> NAME | '(' expr ')' */
+  switch (ls->t.token) {
+    case '(': {
+      int line = ls->linenumber;
+      luaX_next(ls);
+      expr(ls, v);
+      check_match(ls, ')', '(', line);
+      luaK_dischargevars(ls->fs, v);
+      return;
+    }
+    case TK_NAME: {
+      singlevar(ls, v);
+      return;
+    }
+    default: {
+      luaX_syntaxerror(ls, "unexpected symbol");
+      return;
+    }
+  }
+}
+
+
+static void primaryexp (LexState *ls, expdesc *v) {
+  /* primaryexp ->
+        prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
+  FuncState *fs = ls->fs;
+  prefixexp(ls, v);
+  for (;;) {
+    switch (ls->t.token) {
+      case '.': {  /* field */
+        field(ls, v);
+        break;
+      }
+      case '[': {  /* `[' exp1 `]' */
+        expdesc key;
+        luaK_exp2anyreg(fs, v);
+        yindex(ls, &key);
+        luaK_indexed(fs, v, &key);
+        break;
+      }
+      case ':': {  /* `:' NAME funcargs */
+        expdesc key;
+        luaX_next(ls);
+        checkname(ls, &key);
+        luaK_self(fs, v, &key);
+        funcargs(ls, v);
+        break;
+      }
+      case '(': case TK_STRING: case '{': {  /* funcargs */
+        luaK_exp2nextreg(fs, v);
+        funcargs(ls, v);
+        break;
+      }
+      default: return;
+    }
+  }
+}
+
+
+static void simpleexp (LexState *ls, expdesc *v) {
+  /* simpleexp -> NUMBER | STRING | NIL | true | false | ... |
+                  constructor | FUNCTION body | primaryexp */
+  switch (ls->t.token) {
+    case TK_NUMBER: {
+      init_exp(v, VKNUM, 0);
+      v->u.nval = ls->t.seminfo.r;
+      break;
+    }
+    case TK_STRING: {
+      codestring(ls, v, ls->t.seminfo.ts);
+      break;
+    }
+    case TK_NIL: {
+      init_exp(v, VNIL, 0);
+      break;
+    }
+    case TK_TRUE: {
+      init_exp(v, VTRUE, 0);
+      break;
+    }
+    case TK_FALSE: {
+      init_exp(v, VFALSE, 0);
+      break;
+    }
+    case TK_DOTS: {  /* vararg */
+      FuncState *fs = ls->fs;
+      check_condition(ls, fs->f->is_vararg,
+                      "cannot use " LUA_QL("...") " outside a vararg function");
+      fs->f->is_vararg &= ~VARARG_NEEDSARG;  /* don't need 'arg' */
+      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
+      break;
+    }
+    case '{': {  /* constructor */
+      constructor(ls, v);
+      return;
+    }
+    case TK_FUNCTION: {
+      luaX_next(ls);
+      body(ls, v, 0, ls->linenumber);
+      return;
+    }
+    default: {
+      primaryexp(ls, v);
+      return;
+    }
+  }
+  luaX_next(ls);
+}
+
+
+static UnOpr getunopr (int op) {
+  switch (op) {
+    case TK_NOT: return OPR_NOT;
+    case '-': return OPR_MINUS;
+    case '#': return OPR_LEN;
+    default: return OPR_NOUNOPR;
+  }
+}
+
+
+static BinOpr getbinopr (int op) {
+  switch (op) {
+    case '+': return OPR_ADD;
+    case '-': return OPR_SUB;
+    case '*': return OPR_MUL;
+    case '/': return OPR_DIV;
+    case '%': return OPR_MOD;
+    case '^': return OPR_POW;
+    case TK_CONCAT: return OPR_CONCAT;
+    case TK_NE: return OPR_NE;
+    case TK_EQ: return OPR_EQ;
+    case '<': return OPR_LT;
+    case TK_LE: return OPR_LE;
+    case '>': return OPR_GT;
+    case TK_GE: return OPR_GE;
+    case TK_AND: return OPR_AND;
+    case TK_OR: return OPR_OR;
+    default: return OPR_NOBINOPR;
+  }
+}
+
+
+static const struct {
+  lu_byte left;  /* left priority for each binary operator */
+  lu_byte right; /* right priority */
+} priority[] = {  /* ORDER OPR */
+   {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7},  /* `+' `-' `/' `%' */
+   {10, 9}, {5, 4},                 /* power and concat (right associative) */
+   {3, 3}, {3, 3},                  /* equality and inequality */
+   {3, 3}, {3, 3}, {3, 3}, {3, 3},  /* order */
+   {2, 2}, {1, 1}                   /* logical (and/or) */
+};
+
+#define UNARY_PRIORITY	8  /* priority for unary operators */
+
+
+/*
+** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
+** where `binop' is any binary operator with a priority higher than `limit'
+*/
+static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
+  BinOpr op;
+  UnOpr uop;
+  enterlevel(ls);
+  uop = getunopr(ls->t.token);
+  if (uop != OPR_NOUNOPR) {
+    luaX_next(ls);
+    subexpr(ls, v, UNARY_PRIORITY);
+    luaK_prefix(ls->fs, uop, v);
+  }
+  else simpleexp(ls, v);
+  /* expand while operators have priorities higher than `limit' */
+  op = getbinopr(ls->t.token);
+  while (op != OPR_NOBINOPR && priority[op].left > limit) {
+    expdesc v2;
+    BinOpr nextop;
+    luaX_next(ls);
+    luaK_infix(ls->fs, op, v);
+    /* read sub-expression with higher priority */
+    nextop = subexpr(ls, &v2, priority[op].right);
+    luaK_posfix(ls->fs, op, v, &v2);
+    op = nextop;
+  }
+  leavelevel(ls);
+  return op;  /* return first untreated operator */
+}
+
+
+static void expr (LexState *ls, expdesc *v) {
+  subexpr(ls, v, 0);
+}
+
+/* }==================================================================== */
+
+
+
+/*
+** {======================================================================
+** Rules for Statements
+** =======================================================================
+*/
+
+
+static int block_follow (int token) {
+  switch (token) {
+    case TK_ELSE: case TK_ELSEIF: case TK_END:
+    case TK_UNTIL: case TK_EOS:
+      return 1;
+    default: return 0;
+  }
+}
+
+
+static void block (LexState *ls) {
+  /* block -> chunk */
+  FuncState *fs = ls->fs;
+  BlockCnt bl;
+  enterblock(fs, &bl, 0);
+  chunk(ls);
+  lua_assert(bl.breaklist == NO_JUMP);
+  leaveblock(fs);
+}
+
+
+/*
+** structure to chain all variables in the left-hand side of an
+** assignment
+*/
+struct LHS_assign {
+  struct LHS_assign *prev;
+  expdesc v;  /* variable (global, local, upvalue, or indexed) */
+};
+
+
+/*
+** check whether, in an assignment to a local variable, the local variable
+** is needed in a previous assignment (to a table). If so, save original
+** local value in a safe place and use this safe copy in the previous
+** assignment.
+*/
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+  FuncState *fs = ls->fs;
+  int extra = fs->freereg;  /* eventual position to save local variable */
+  int conflict = 0;
+  for (; lh; lh = lh->prev) {
+    if (lh->v.k == VINDEXED) {
+      if (lh->v.u.s.info == v->u.s.info) {  /* conflict? */
+        conflict = 1;
+        lh->v.u.s.info = extra;  /* previous assignment will use safe copy */
+      }
+      if (lh->v.u.s.aux == v->u.s.info) {  /* conflict? */
+        conflict = 1;
+        lh->v.u.s.aux = extra;  /* previous assignment will use safe copy */
+      }
+    }
+  }
+  if (conflict) {
+    luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0);  /* make copy */
+    luaK_reserveregs(fs, 1);
+  }
+}
+
+
+static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
+  expdesc e;
+  check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
+                      "syntax error");
+  if (testnext(ls, ',')) {  /* assignment -> `,' primaryexp assignment */
+    struct LHS_assign nv;
+    nv.prev = lh;
+    primaryexp(ls, &nv.v);
+    if (nv.v.k == VLOCAL)
+      check_conflict(ls, lh, &nv.v);
+    luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls,
+                    "variables in assignment");
+    assignment(ls, &nv, nvars+1);
+  }
+  else {  /* assignment -> `=' explist1 */
+    int nexps;
+    checknext(ls, '=');
+    nexps = explist1(ls, &e);
+    if (nexps != nvars) {
+      adjust_assign(ls, nvars, nexps, &e);
+      if (nexps > nvars)
+        ls->fs->freereg -= nexps - nvars;  /* remove extra values */
+    }
+    else {
+      luaK_setoneret(ls->fs, &e);  /* close last expression */
+      luaK_storevar(ls->fs, &lh->v, &e);
+      return;  /* avoid default */
+    }
+  }
+  init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
+  luaK_storevar(ls->fs, &lh->v, &e);
+}
+
+
+static int cond (LexState *ls) {
+  /* cond -> exp */
+  expdesc v;
+  expr(ls, &v);  /* read condition */
+  if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
+  luaK_goiftrue(ls->fs, &v);
+  return v.f;
+}
+
+
+static void breakstat (LexState *ls) {
+  FuncState *fs = ls->fs;
+  BlockCnt *bl = fs->bl;
+  int upval = 0;
+  while (bl && !bl->isbreakable) {
+    upval |= bl->upval;
+    bl = bl->previous;
+  }
+  if (!bl)
+    luaX_syntaxerror(ls, "no loop to break");
+  if (upval)
+    luaK_codeABC(fs, OP_CLOSE, bl->nactvar, 0, 0);
+  luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
+}
+
+
+static void whilestat (LexState *ls, int line) {
+  /* whilestat -> WHILE cond DO block END */
+  FuncState *fs = ls->fs;
+  int whileinit;
+  int condexit;
+  BlockCnt bl;
+  luaX_next(ls);  /* skip WHILE */
+  whileinit = luaK_getlabel(fs);
+  condexit = cond(ls);
+  enterblock(fs, &bl, 1);
+  checknext(ls, TK_DO);
+  block(ls);
+  luaK_patchlist(fs, luaK_jump(fs), whileinit);
+  check_match(ls, TK_END, TK_WHILE, line);
+  leaveblock(fs);
+  luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
+}
+
+
+static void repeatstat (LexState *ls, int line) {
+  /* repeatstat -> REPEAT block UNTIL cond */
+  int condexit;
+  FuncState *fs = ls->fs;
+  int repeat_init = luaK_getlabel(fs);
+  BlockCnt bl1, bl2;
+  enterblock(fs, &bl1, 1);  /* loop block */
+  enterblock(fs, &bl2, 0);  /* scope block */
+  luaX_next(ls);  /* skip REPEAT */
+  chunk(ls);
+  check_match(ls, TK_UNTIL, TK_REPEAT, line);
+  condexit = cond(ls);  /* read condition (inside scope block) */
+  if (!bl2.upval) {  /* no upvalues? */
+    leaveblock(fs);  /* finish scope */
+    luaK_patchlist(ls->fs, condexit, repeat_init);  /* close the loop */
+  }
+  else {  /* complete semantics when there are upvalues */
+    breakstat(ls);  /* if condition then break */
+    luaK_patchtohere(ls->fs, condexit);  /* else... */
+    leaveblock(fs);  /* finish scope... */
+    luaK_patchlist(ls->fs, luaK_jump(fs), repeat_init);  /* and repeat */
+  }
+  leaveblock(fs);  /* finish loop */
+}
+
+
+static int exp1 (LexState *ls) {
+  expdesc e;
+  int k;
+  expr(ls, &e);
+  k = e.k;
+  luaK_exp2nextreg(ls->fs, &e);
+  return k;
+}
+
+
+static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
+  /* forbody -> DO block */
+  BlockCnt bl;
+  FuncState *fs = ls->fs;
+  int prep, endfor;
+  adjustlocalvars(ls, 3);  /* control variables */
+  checknext(ls, TK_DO);
+  prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
+  enterblock(fs, &bl, 0);  /* scope for declared variables */
+  adjustlocalvars(ls, nvars);
+  luaK_reserveregs(fs, nvars);
+  block(ls);
+  leaveblock(fs);  /* end of scope for declared variables */
+  luaK_patchtohere(fs, prep);
+  endfor = (isnum) ? luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP) :
+                     luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
+  luaK_fixline(fs, line);  /* pretend that `OP_FOR' starts the loop */
+  luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
+}
+
+
+static void fornum (LexState *ls, TString *varname, int line) {
+  /* fornum -> NAME = exp1,exp1[,exp1] forbody */
+  FuncState *fs = ls->fs;
+  int base = fs->freereg;
+  new_localvarliteral(ls, "(for index)", 0);
+  new_localvarliteral(ls, "(for limit)", 1);
+  new_localvarliteral(ls, "(for step)", 2);
+  new_localvar(ls, varname, 3);
+  checknext(ls, '=');
+  exp1(ls);  /* initial value */
+  checknext(ls, ',');
+  exp1(ls);  /* limit */
+  if (testnext(ls, ','))
+    exp1(ls);  /* optional step */
+  else {  /* default step = 1 */
+    luaK_codeABx(fs, OP_LOADK, fs->freereg, luaK_numberK(fs, 1));
+    luaK_reserveregs(fs, 1);
+  }
+  forbody(ls, base, line, 1, 1);
+}
+
+
+static void forlist (LexState *ls, TString *indexname) {
+  /* forlist -> NAME {,NAME} IN explist1 forbody */
+  FuncState *fs = ls->fs;
+  expdesc e;
+  int nvars = 0;
+  int line;
+  int base = fs->freereg;
+  /* create control variables */
+  new_localvarliteral(ls, "(for generator)", nvars++);
+  new_localvarliteral(ls, "(for state)", nvars++);
+  new_localvarliteral(ls, "(for control)", nvars++);
+  /* create declared variables */
+  new_localvar(ls, indexname, nvars++);
+  while (testnext(ls, ','))
+    new_localvar(ls, str_checkname(ls), nvars++);
+  checknext(ls, TK_IN);
+  line = ls->linenumber;
+  adjust_assign(ls, 3, explist1(ls, &e), &e);
+  luaK_checkstack(fs, 3);  /* extra space to call generator */
+  forbody(ls, base, line, nvars - 3, 0);
+}
+
+
+static void forstat (LexState *ls, int line) {
+  /* forstat -> FOR (fornum | forlist) END */
+  FuncState *fs = ls->fs;
+  TString *varname;
+  BlockCnt bl;
+  enterblock(fs, &bl, 1);  /* scope for loop and control variables */
+  luaX_next(ls);  /* skip `for' */
+  varname = str_checkname(ls);  /* first variable name */
+  switch (ls->t.token) {
+    case '=': fornum(ls, varname, line); break;
+    case ',': case TK_IN: forlist(ls, varname); break;
+    default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
+  }
+  check_match(ls, TK_END, TK_FOR, line);
+  leaveblock(fs);  /* loop scope (`break' jumps to this point) */
+}
+
+
+static int test_then_block (LexState *ls) {
+  /* test_then_block -> [IF | ELSEIF] cond THEN block */
+  int condexit;
+  luaX_next(ls);  /* skip IF or ELSEIF */
+  condexit = cond(ls);
+  checknext(ls, TK_THEN);
+  block(ls);  /* `then' part */
+  return condexit;
+}
+
+
+static void ifstat (LexState *ls, int line) {
+  /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
+  FuncState *fs = ls->fs;
+  int flist;
+  int escapelist = NO_JUMP;
+  flist = test_then_block(ls);  /* IF cond THEN block */
+  while (ls->t.token == TK_ELSEIF) {
+    luaK_concat(fs, &escapelist, luaK_jump(fs));
+    luaK_patchtohere(fs, flist);
+    flist = test_then_block(ls);  /* ELSEIF cond THEN block */
+  }
+  if (ls->t.token == TK_ELSE) {
+    luaK_concat(fs, &escapelist, luaK_jump(fs));
+    luaK_patchtohere(fs, flist);
+    luaX_next(ls);  /* skip ELSE (after patch, for correct line info) */
+    block(ls);  /* `else' part */
+  }
+  else
+    luaK_concat(fs, &escapelist, flist);
+  luaK_patchtohere(fs, escapelist);
+  check_match(ls, TK_END, TK_IF, line);
+}
+
+
+static void localfunc (LexState *ls) {
+  expdesc v, b;
+  FuncState *fs = ls->fs;
+  new_localvar(ls, str_checkname(ls), 0);
+  init_exp(&v, VLOCAL, fs->freereg);
+  luaK_reserveregs(fs, 1);
+  adjustlocalvars(ls, 1);
+  body(ls, &b, 0, ls->linenumber);
+  luaK_storevar(fs, &v, &b);
+  /* debug information will only see the variable after this point! */
+  getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
+}
+
+
+static void localstat (LexState *ls) {
+  /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
+  int nvars = 0;
+  int nexps;
+  expdesc e;
+  do {
+    new_localvar(ls, str_checkname(ls), nvars++);
+  } while (testnext(ls, ','));
+  if (testnext(ls, '='))
+    nexps = explist1(ls, &e);
+  else {
+    e.k = VVOID;
+    nexps = 0;
+  }
+  adjust_assign(ls, nvars, nexps, &e);
+  adjustlocalvars(ls, nvars);
+}
+
+
+static int funcname (LexState *ls, expdesc *v) {
+  /* funcname -> NAME {field} [`:' NAME] */
+  int needself = 0;
+  singlevar(ls, v);
+  while (ls->t.token == '.')
+    field(ls, v);
+  if (ls->t.token == ':') {
+    needself = 1;
+    field(ls, v);
+  }
+  return needself;
+}
+
+
+static void funcstat (LexState *ls, int line) {
+  /* funcstat -> FUNCTION funcname body */
+  int needself;
+  expdesc v, b;
+  luaX_next(ls);  /* skip FUNCTION */
+  needself = funcname(ls, &v);
+  body(ls, &b, needself, line);
+  luaK_storevar(ls->fs, &v, &b);
+  luaK_fixline(ls->fs, line);  /* definition `happens' in the first line */
+}
+
+
+static void exprstat (LexState *ls) {
+  /* stat -> func | assignment */
+  FuncState *fs = ls->fs;
+  struct LHS_assign v;
+  primaryexp(ls, &v.v);
+  if (v.v.k == VCALL)  /* stat -> func */
+    SETARG_C(getcode(fs, &v.v), 1);  /* call statement uses no results */
+  else {  /* stat -> assignment */
+    v.prev = NULL;
+    assignment(ls, &v, 1);
+  }
+}
+
+
+static void retstat (LexState *ls) {
+  /* stat -> RETURN explist */
+  FuncState *fs = ls->fs;
+  expdesc e;
+  int first, nret;  /* registers with returned values */
+  luaX_next(ls);  /* skip RETURN */
+  if (block_follow(ls->t.token) || ls->t.token == ';')
+    first = nret = 0;  /* return no values */
+  else {
+    nret = explist1(ls, &e);  /* optional return values */
+    if (hasmultret(e.k)) {
+      luaK_setmultret(fs, &e);
+      if (e.k == VCALL && nret == 1) {  /* tail call? */
+        SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
+        lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
+      }
+      first = fs->nactvar;
+      nret = LUA_MULTRET;  /* return all values */
+    }
+    else {
+      if (nret == 1)  /* only one single value? */
+        first = luaK_exp2anyreg(fs, &e);
+      else {
+        luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
+        first = fs->nactvar;  /* return all `active' values */
+        lua_assert(nret == fs->freereg - first);
+      }
+    }
+  }
+  luaK_ret(fs, first, nret);
+}
+
+
+static int statement (LexState *ls) {
+  int line = ls->linenumber;  /* may be needed for error messages */
+  switch (ls->t.token) {
+    case TK_IF: {  /* stat -> ifstat */
+      ifstat(ls, line);
+      return 0;
+    }
+    case TK_WHILE: {  /* stat -> whilestat */
+      whilestat(ls, line);
+      return 0;
+    }
+    case TK_DO: {  /* stat -> DO block END */
+      luaX_next(ls);  /* skip DO */
+      block(ls);
+      check_match(ls, TK_END, TK_DO, line);
+      return 0;
+    }
+    case TK_FOR: {  /* stat -> forstat */
+      forstat(ls, line);
+      return 0;
+    }
+    case TK_REPEAT: {  /* stat -> repeatstat */
+      repeatstat(ls, line);
+      return 0;
+    }
+    case TK_FUNCTION: {
+      funcstat(ls, line);  /* stat -> funcstat */
+      return 0;
+    }
+    case TK_LOCAL: {  /* stat -> localstat */
+      luaX_next(ls);  /* skip LOCAL */
+      if (testnext(ls, TK_FUNCTION))  /* local function? */
+        localfunc(ls);
+      else
+        localstat(ls);
+      return 0;
+    }
+    case TK_RETURN: {  /* stat -> retstat */
+      retstat(ls);
+      return 1;  /* must be last statement */
+    }
+    case TK_BREAK: {  /* stat -> breakstat */
+      luaX_next(ls);  /* skip BREAK */
+      breakstat(ls);
+      return 1;  /* must be last statement */
+    }
+    default: {
+      exprstat(ls);
+      return 0;  /* to avoid warnings */
+    }
+  }
+}
+
+
+static void chunk (LexState *ls) {
+  /* chunk -> { stat [`;'] } */
+  int islast = 0;
+  enterlevel(ls);
+  while (!islast && !block_follow(ls->t.token)) {
+    islast = statement(ls);
+    testnext(ls, ';');
+    lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
+               ls->fs->freereg >= ls->fs->nactvar);
+    ls->fs->freereg = ls->fs->nactvar;  /* free registers */
+  }
+  leavelevel(ls);
+}
+
+/* }====================================================================== */

=== added file 'lua/lparser.h'
--- lua/lparser.h	1970-01-01 00:00:00 +0000
+++ lua/lparser.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,82 @@
+/*
+** $Id: lparser.h,v 1.57.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lua Parser
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lparser_h
+#define lparser_h
+
+#include "llimits.h"
+#include "lobject.h"
+#include "lzio.h"
+
+
+/*
+** Expression descriptor
+*/
+
+typedef enum {
+  VVOID,	/* no value */
+  VNIL,
+  VTRUE,
+  VFALSE,
+  VK,		/* info = index of constant in `k' */
+  VKNUM,	/* nval = numerical value */
+  VLOCAL,	/* info = local register */
+  VUPVAL,       /* info = index of upvalue in `upvalues' */
+  VGLOBAL,	/* info = index of table; aux = index of global name in `k' */
+  VINDEXED,	/* info = table register; aux = index register (or `k') */
+  VJMP,		/* info = instruction pc */
+  VRELOCABLE,	/* info = instruction pc */
+  VNONRELOC,	/* info = result register */
+  VCALL,	/* info = instruction pc */
+  VVARARG	/* info = instruction pc */
+} expkind;
+
+typedef struct expdesc {
+  expkind k;
+  union {
+    struct { int info, aux; } s;
+    lua_Number nval;
+  } u;
+  int t;  /* patch list of `exit when true' */
+  int f;  /* patch list of `exit when false' */
+} expdesc;
+
+
+typedef struct upvaldesc {
+  lu_byte k;
+  lu_byte info;
+} upvaldesc;
+
+
+struct BlockCnt;  /* defined in lparser.c */
+
+
+/* state needed to generate code for a given function */
+typedef struct FuncState {
+  Proto *f;  /* current function header */
+  Table *h;  /* table to find (and reuse) elements in `k' */
+  struct FuncState *prev;  /* enclosing function */
+  struct LexState *ls;  /* lexical state */
+  struct lua_State *L;  /* copy of the Lua state */
+  struct BlockCnt *bl;  /* chain of current blocks */
+  int pc;  /* next position to code (equivalent to `ncode') */
+  int lasttarget;   /* `pc' of last `jump target' */
+  int jpc;  /* list of pending jumps to `pc' */
+  int freereg;  /* first free register */
+  int nk;  /* number of elements in `k' */
+  int np;  /* number of elements in `p' */
+  short nlocvars;  /* number of elements in `locvars' */
+  lu_byte nactvar;  /* number of active local variables */
+  upvaldesc upvalues[LUAI_MAXUPVALUES];  /* upvalues */
+  unsigned short actvar[LUAI_MAXVARS];  /* declared-variable stack */
+} FuncState;
+
+
+LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+                                            const char *name);
+
+
+#endif

=== added file 'lua/lstate.c'
--- lua/lstate.c	1970-01-01 00:00:00 +0000
+++ lua/lstate.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,216 @@
+/*
+** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stddef.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lstate_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "llex.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+#define state_size(x)	(sizeof(x) + LUAI_EXTRASPACE)
+#define fromstate(l)	(cast(lu_byte *, (l)) - LUAI_EXTRASPACE)
+#define tostate(l)   (cast(lua_State *, cast(lu_byte *, l) + LUAI_EXTRASPACE))
+
+
+/*
+** Main thread combines a thread state and the global state
+*/
+typedef struct LG {
+  lua_State l;
+  global_State g;
+} LG;
+  
+
+
+static void stack_init (lua_State *L1, lua_State *L) {
+  /* initialize CallInfo array */
+  L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
+  L1->ci = L1->base_ci;
+  L1->size_ci = BASIC_CI_SIZE;
+  L1->end_ci = L1->base_ci + L1->size_ci - 1;
+  /* initialize stack array */
+  L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);
+  L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
+  L1->top = L1->stack;
+  L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
+  /* initialize first ci */
+  L1->ci->func = L1->top;
+  setnilvalue(L1->top++);  /* `function' entry for this `ci' */
+  L1->base = L1->ci->base = L1->top;
+  L1->ci->top = L1->top + LUA_MINSTACK;
+}
+
+
+static void freestack (lua_State *L, lua_State *L1) {
+  luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
+  luaM_freearray(L, L1->stack, L1->stacksize, TValue);
+}
+
+
+/*
+** open parts that may cause memory-allocation errors
+*/
+static void f_luaopen (lua_State *L, void *ud) {
+  global_State *g = G(L);
+  UNUSED(ud);
+  stack_init(L, L);  /* init stack */
+  sethvalue(L, gt(L), luaH_new(L, 0, 2));  /* table of globals */
+  sethvalue(L, registry(L), luaH_new(L, 0, 2));  /* registry */
+  luaS_resize(L, MINSTRTABSIZE);  /* initial size of string table */
+  luaT_init(L);
+  luaX_init(L);
+  luaS_fix(luaS_newliteral(L, MEMERRMSG));
+  g->GCthreshold = 4*g->totalbytes;
+}
+
+
+static void preinit_state (lua_State *L, global_State *g) {
+  G(L) = g;
+  L->stack = NULL;
+  L->stacksize = 0;
+  L->errorJmp = NULL;
+  L->hook = NULL;
+  L->hookmask = 0;
+  L->basehookcount = 0;
+  L->allowhook = 1;
+  resethookcount(L);
+  L->openupval = NULL;
+  L->size_ci = 0;
+  L->nCcalls = L->baseCcalls = 0;
+  L->status = 0;
+  L->base_ci = L->ci = NULL;
+  L->savedpc = NULL;
+  L->errfunc = 0;
+  setnilvalue(gt(L));
+}
+
+
+static void close_state (lua_State *L) {
+  global_State *g = G(L);
+  luaF_close(L, L->stack);  /* close all upvalues for this thread */
+  luaC_freeall(L);  /* collect all objects */
+  lua_assert(g->rootgc == obj2gco(L));
+  lua_assert(g->strt.nuse == 0);
+  luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
+  luaZ_freebuffer(L, &g->buff);
+  freestack(L, L);
+  lua_assert(g->totalbytes == sizeof(LG));
+  (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0);
+}
+
+
+lua_State *luaE_newthread (lua_State *L) {
+  lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
+  luaC_link(L, obj2gco(L1), LUA_TTHREAD);
+  preinit_state(L1, G(L));
+  stack_init(L1, L);  /* init stack */
+  setobj2n(L, gt(L1), gt(L));  /* share table of globals */
+  L1->hookmask = L->hookmask;
+  L1->basehookcount = L->basehookcount;
+  L1->hook = L->hook;
+  resethookcount(L1);
+  lua_assert(iswhite(obj2gco(L1)));
+  return L1;
+}
+
+
+void luaE_freethread (lua_State *L, lua_State *L1) {
+  luaF_close(L1, L1->stack);  /* close all upvalues for this thread */
+  lua_assert(L1->openupval == NULL);
+  luai_userstatefree(L1);
+  freestack(L, L1);
+  luaM_freemem(L, fromstate(L1), state_size(lua_State));
+}
+
+
+LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
+  int i;
+  lua_State *L;
+  global_State *g;
+  void *l = (*f)(ud, NULL, 0, state_size(LG));
+  if (l == NULL) return NULL;
+  L = tostate(l);
+  g = &((LG *)L)->g;
+  L->next = NULL;
+  L->tt = LUA_TTHREAD;
+  g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
+  L->marked = luaC_white(g);
+  set2bits(L->marked, FIXEDBIT, SFIXEDBIT);
+  preinit_state(L, g);
+  g->frealloc = f;
+  g->ud = ud;
+  g->mainthread = L;
+  g->uvhead.u.l.prev = &g->uvhead;
+  g->uvhead.u.l.next = &g->uvhead;
+  g->GCthreshold = 0;  /* mark it as unfinished state */
+  g->strt.size = 0;
+  g->strt.nuse = 0;
+  g->strt.hash = NULL;
+  setnilvalue(registry(L));
+  luaZ_initbuffer(L, &g->buff);
+  g->panic = NULL;
+  g->gcstate = GCSpause;
+  g->rootgc = obj2gco(L);
+  g->sweepstrgc = 0;
+  g->sweepgc = &g->rootgc;
+  g->gray = NULL;
+  g->grayagain = NULL;
+  g->weak = NULL;
+  g->tmudata = NULL;
+  g->totalbytes = sizeof(LG);
+  g->gcpause = LUAI_GCPAUSE;
+  g->gcstepmul = LUAI_GCMUL;
+  g->gcdept = 0;
+  for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
+  if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
+    /* memory allocation error: free partial state */
+    close_state(L);
+    L = NULL;
+  }
+  else
+    luai_userstateopen(L);
+  return L;
+}
+
+
+static void callallgcTM (lua_State *L, void *ud) {
+  UNUSED(ud);
+  luaC_callGCTM(L);  /* call GC metamethods for all udata */
+}
+
+
+LUA_API void lua_close (lua_State *L) {
+  L = G(L)->mainthread;  /* only the main thread can be closed */
+  lua_lock(L);
+  luaF_close(L, L->stack);  /* close all upvalues for this thread */
+  luaC_separateudata(L, 1);  /* separate udata that have GC metamethods */
+  L->errfunc = 0;  /* no error function during GC metamethods */
+  do {  /* repeat until no more errors */
+    L->ci = L->base_ci;
+    L->base = L->top = L->ci->base;
+    L->nCcalls = L->baseCcalls = 0;
+  } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
+  lua_assert(G(L)->tmudata == NULL);
+  luai_userstateclose(L);
+  close_state(L);
+}
+

=== added file 'lua/lstate.h'
--- lua/lstate.h	1970-01-01 00:00:00 +0000
+++ lua/lstate.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,169 @@
+/*
+** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $
+** Global State
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstate_h
+#define lstate_h
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "ltm.h"
+#include "lzio.h"
+
+
+
+struct lua_longjmp;  /* defined in ldo.c */
+
+
+/* table of globals */
+#define gt(L)	(&L->l_gt)
+
+/* registry */
+#define registry(L)	(&G(L)->l_registry)
+
+
+/* extra stack space to handle TM calls and some other extras */
+#define EXTRA_STACK   5
+
+
+#define BASIC_CI_SIZE           8
+
+#define BASIC_STACK_SIZE        (2*LUA_MINSTACK)
+
+
+
+typedef struct stringtable {
+  GCObject **hash;
+  lu_int32 nuse;  /* number of elements */
+  int size;
+} stringtable;
+
+
+/*
+** informations about a call
+*/
+typedef struct CallInfo {
+  StkId base;  /* base for this function */
+  StkId func;  /* function index in the stack */
+  StkId	top;  /* top for this function */
+  const Instruction *savedpc;
+  int nresults;  /* expected number of results from this function */
+  int tailcalls;  /* number of tail calls lost under this entry */
+} CallInfo;
+
+
+
+#define curr_func(L)	(clvalue(L->ci->func))
+#define ci_func(ci)	(clvalue((ci)->func))
+#define f_isLua(ci)	(!ci_func(ci)->c.isC)
+#define isLua(ci)	(ttisfunction((ci)->func) && f_isLua(ci))
+
+
+/*
+** `global state', shared by all threads of this state
+*/
+typedef struct global_State {
+  stringtable strt;  /* hash table for strings */
+  lua_Alloc frealloc;  /* function to reallocate memory */
+  void *ud;         /* auxiliary data to `frealloc' */
+  lu_byte currentwhite;
+  lu_byte gcstate;  /* state of garbage collector */
+  int sweepstrgc;  /* position of sweep in `strt' */
+  GCObject *rootgc;  /* list of all collectable objects */
+  GCObject **sweepgc;  /* position of sweep in `rootgc' */
+  GCObject *gray;  /* list of gray objects */
+  GCObject *grayagain;  /* list of objects to be traversed atomically */
+  GCObject *weak;  /* list of weak tables (to be cleared) */
+  GCObject *tmudata;  /* last element of list of userdata to be GC */
+  Mbuffer buff;  /* temporary buffer for string concatentation */
+  lu_mem GCthreshold;
+  lu_mem totalbytes;  /* number of bytes currently allocated */
+  lu_mem estimate;  /* an estimate of number of bytes actually in use */
+  lu_mem gcdept;  /* how much GC is `behind schedule' */
+  int gcpause;  /* size of pause between successive GCs */
+  int gcstepmul;  /* GC `granularity' */
+  lua_CFunction panic;  /* to be called in unprotected errors */
+  TValue l_registry;
+  struct lua_State *mainthread;
+  UpVal uvhead;  /* head of double-linked list of all open upvalues */
+  struct Table *mt[NUM_TAGS];  /* metatables for basic types */
+  TString *tmname[TM_N];  /* array with tag-method names */
+} global_State;
+
+
+/*
+** `per thread' state
+*/
+struct lua_State {
+  CommonHeader;
+  lu_byte status;
+  StkId top;  /* first free slot in the stack */
+  StkId base;  /* base of current function */
+  global_State *l_G;
+  CallInfo *ci;  /* call info for current function */
+  const Instruction *savedpc;  /* `savedpc' of current function */
+  StkId stack_last;  /* last free slot in the stack */
+  StkId stack;  /* stack base */
+  CallInfo *end_ci;  /* points after end of ci array*/
+  CallInfo *base_ci;  /* array of CallInfo's */
+  int stacksize;
+  int size_ci;  /* size of array `base_ci' */
+  unsigned short nCcalls;  /* number of nested C calls */
+  unsigned short baseCcalls;  /* nested C calls when resuming coroutine */
+  lu_byte hookmask;
+  lu_byte allowhook;
+  int basehookcount;
+  int hookcount;
+  lua_Hook hook;
+  TValue l_gt;  /* table of globals */
+  TValue env;  /* temporary place for environments */
+  GCObject *openupval;  /* list of open upvalues in this stack */
+  GCObject *gclist;
+  struct lua_longjmp *errorJmp;  /* current error recover point */
+  ptrdiff_t errfunc;  /* current error handling function (stack index) */
+};
+
+
+#define G(L)	(L->l_G)
+
+
+/*
+** Union of all collectable objects
+*/
+union GCObject {
+  GCheader gch;
+  union TString ts;
+  union Udata u;
+  union Closure cl;
+  struct Table h;
+  struct Proto p;
+  struct UpVal uv;
+  struct lua_State th;  /* thread */
+};
+
+
+/* macros to convert a GCObject into a specific value */
+#define rawgco2ts(o)	check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
+#define gco2ts(o)	(&rawgco2ts(o)->tsv)
+#define rawgco2u(o)	check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
+#define gco2u(o)	(&rawgco2u(o)->uv)
+#define gco2cl(o)	check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
+#define gco2h(o)	check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
+#define gco2p(o)	check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
+#define gco2uv(o)	check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
+#define ngcotouv(o) \
+	check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv))
+#define gco2th(o)	check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
+
+/* macro to convert any Lua object into a GCObject */
+#define obj2gco(v)	(cast(GCObject *, (v)))
+
+
+LUAI_FUNC lua_State *luaE_newthread (lua_State *L);
+LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
+
+#endif
+

=== added file 'lua/lstring.c'
--- lua/lstring.c	1970-01-01 00:00:00 +0000
+++ lua/lstring.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,113 @@
+/*
+** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** String table (keeps all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lstring_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+
+
+
+void luaS_resize (lua_State *L, int newsize) {
+  GCObject **newhash;
+  stringtable *tb;
+  int i;
+  if (G(L)->gcstate == GCSsweepstring)
+    return;  /* cannot resize during GC traverse */
+  newhash = luaM_newvector(L, newsize, GCObject *);
+  tb = &G(L)->strt;
+  for (i=0; i<newsize; i++) newhash[i] = NULL;
+  /* rehash */
+  for (i=0; i<tb->size; i++) {
+    GCObject *p = tb->hash[i];
+    while (p) {  /* for each node in the list */
+      GCObject *next = p->gch.next;  /* save next */
+      unsigned int h = gco2ts(p)->hash;
+      int h1 = lmod(h, newsize);  /* new position */
+      lua_assert(cast_int(h%newsize) == lmod(h, newsize));
+      p->gch.next = newhash[h1];  /* chain it */
+      newhash[h1] = p;
+      p = next;
+    }
+  }
+  luaM_freearray(L, tb->hash, tb->size, TString *);
+  tb->size = newsize;
+  tb->hash = newhash;
+}
+
+
+static TString *newlstr (lua_State *L, const char *str, size_t l,
+                                       unsigned int h) {
+  TString *ts;
+  stringtable *tb;
+  if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
+    luaM_toobig(L);
+  ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
+  ts->tsv.len = l;
+  ts->tsv.hash = h;
+  ts->tsv.marked = luaC_white(G(L));
+  ts->tsv.tt = LUA_TSTRING;
+  ts->tsv.reserved = 0;
+  memcpy(ts+1, str, l*sizeof(char));
+  ((char *)(ts+1))[l] = '\0';  /* ending 0 */
+  tb = &G(L)->strt;
+  h = lmod(h, tb->size);
+  ts->tsv.next = tb->hash[h];  /* chain new entry */
+  tb->hash[h] = obj2gco(ts);
+  tb->nuse++;
+  if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+    luaS_resize(L, tb->size*2);  /* too crowded */
+  return ts;
+}
+
+
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+  GCObject *o;
+  unsigned int h = cast(unsigned int, l);  /* seed */
+  size_t step = (l>>5)+1;  /* if string is too long, don't hash all its chars */
+  size_t l1;
+  for (l1=l; l1>=step; l1-=step)  /* compute hash */
+    h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
+  for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
+       o != NULL;
+       o = o->gch.next) {
+    TString *ts = rawgco2ts(o);
+    if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
+      /* string may be dead */
+      if (isdead(G(L), o)) changewhite(o);
+      return ts;
+    }
+  }
+  return newlstr(L, str, l, h);  /* not found */
+}
+
+
+Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
+  Udata *u;
+  if (s > MAX_SIZET - sizeof(Udata))
+    luaM_toobig(L);
+  u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata)));
+  u->uv.marked = luaC_white(G(L));  /* is not finalized */
+  u->uv.tt = LUA_TUSERDATA;
+  u->uv.len = s;
+  u->uv.metatable = NULL;
+  u->uv.env = e;
+  /* chain it on udata list (after main thread) */
+  u->uv.next = G(L)->mainthread->next;
+  G(L)->mainthread->next = obj2gco(u);
+  return u;
+}
+

=== added file 'lua/lstring.h'
--- lua/lstring.h	1970-01-01 00:00:00 +0000
+++ lua/lstring.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,31 @@
+/*
+** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $
+** String table (keep all strings handled by Lua)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lstring_h
+#define lstring_h
+
+
+#include "lgc.h"
+#include "lobject.h"
+#include "lstate.h"
+
+
+#define sizestring(s)	(sizeof(union TString)+((s)->len+1)*sizeof(char))
+
+#define sizeudata(u)	(sizeof(union Udata)+(u)->len)
+
+#define luaS_new(L, s)	(luaS_newlstr(L, s, strlen(s)))
+#define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
+                                 (sizeof(s)/sizeof(char))-1))
+
+#define luaS_fix(s)	l_setbit((s)->tsv.marked, FIXEDBIT)
+
+LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
+LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
+
+
+#endif

=== added file 'lua/lstrlib.c'
--- lua/lstrlib.c	1970-01-01 00:00:00 +0000
+++ lua/lstrlib.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,872 @@
+/*
+** $Id: lstrlib.c,v 1.132.1.3 2007/12/28 15:32:23 roberto Exp $
+** Standard library for string operations and pattern-matching
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lstrlib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+/* macro to `unsign' a character */
+#define uchar(c)        ((unsigned char)(c))
+
+
+
+static int str_len (lua_State *L) {
+  size_t l;
+  luaL_checklstring(L, 1, &l);
+  lua_pushinteger(L, l);
+  return 1;
+}
+
+
+static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
+  /* relative string position: negative means back from end */
+  return (pos>=0) ? pos : (ptrdiff_t)len+pos+1;
+}
+
+
+static int str_sub (lua_State *L) {
+  size_t l;
+  const char *s = luaL_checklstring(L, 1, &l);
+  ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
+  ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
+  if (start < 1) start = 1;
+  if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
+  if (start <= end)
+    lua_pushlstring(L, s+start-1, end-start+1);
+  else lua_pushliteral(L, "");
+  return 1;
+}
+
+
+static int str_reverse (lua_State *L) {
+  size_t l;
+  luaL_Buffer b;
+  const char *s = luaL_checklstring(L, 1, &l);
+  luaL_buffinit(L, &b);
+  while (l--) luaL_addchar(&b, s[l]);
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static int str_lower (lua_State *L) {
+  size_t l;
+  size_t i;
+  luaL_Buffer b;
+  const char *s = luaL_checklstring(L, 1, &l);
+  luaL_buffinit(L, &b);
+  for (i=0; i<l; i++)
+    luaL_addchar(&b, tolower(uchar(s[i])));
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static int str_upper (lua_State *L) {
+  size_t l;
+  size_t i;
+  luaL_Buffer b;
+  const char *s = luaL_checklstring(L, 1, &l);
+  luaL_buffinit(L, &b);
+  for (i=0; i<l; i++)
+    luaL_addchar(&b, toupper(uchar(s[i])));
+  luaL_pushresult(&b);
+  return 1;
+}
+
+static int str_rep (lua_State *L) {
+  size_t l;
+  luaL_Buffer b;
+  const char *s = luaL_checklstring(L, 1, &l);
+  int n = luaL_checkint(L, 2);
+  luaL_buffinit(L, &b);
+  while (n-- > 0)
+    luaL_addlstring(&b, s, l);
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static int str_byte (lua_State *L) {
+  size_t l;
+  const char *s = luaL_checklstring(L, 1, &l);
+  ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
+  ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
+  int n, i;
+  if (posi <= 0) posi = 1;
+  if ((size_t)pose > l) pose = l;
+  if (posi > pose) return 0;  /* empty interval; return no values */
+  n = (int)(pose -  posi + 1);
+  if (posi + n <= pose)  /* overflow? */
+    luaL_error(L, "string slice too long");
+  luaL_checkstack(L, n, "string slice too long");
+  for (i=0; i<n; i++)
+    lua_pushinteger(L, uchar(s[posi+i-1]));
+  return n;
+}
+
+
+static int str_char (lua_State *L) {
+  int n = lua_gettop(L);  /* number of arguments */
+  int i;
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  for (i=1; i<=n; i++) {
+    int c = luaL_checkint(L, i);
+    luaL_argcheck(L, uchar(c) == c, i, "invalid value");
+    luaL_addchar(&b, uchar(c));
+  }
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static int writer (lua_State *L, const void* b, size_t size, void* B) {
+  (void)L;
+  luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
+  return 0;
+}
+
+
+static int str_dump (lua_State *L) {
+  luaL_Buffer b;
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  lua_settop(L, 1);
+  luaL_buffinit(L,&b);
+  if (lua_dump(L, writer, &b) != 0)
+    luaL_error(L, "unable to dump given function");
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+
+/*
+** {======================================================
+** PATTERN MATCHING
+** =======================================================
+*/
+
+
+#define CAP_UNFINISHED	(-1)
+#define CAP_POSITION	(-2)
+
+typedef struct MatchState {
+  const char *src_init;  /* init of source string */
+  const char *src_end;  /* end (`\0') of source string */
+  lua_State *L;
+  int level;  /* total number of captures (finished or unfinished) */
+  struct {
+    const char *init;
+    ptrdiff_t len;
+  } capture[LUA_MAXCAPTURES];
+} MatchState;
+
+
+#define L_ESC		'%'
+#define SPECIALS	"^$*+?.([%-"
+
+
+static int check_capture (MatchState *ms, int l) {
+  l -= '1';
+  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
+    return luaL_error(ms->L, "invalid capture index");
+  return l;
+}
+
+
+static int capture_to_close (MatchState *ms) {
+  int level = ms->level;
+  for (level--; level>=0; level--)
+    if (ms->capture[level].len == CAP_UNFINISHED) return level;
+  return luaL_error(ms->L, "invalid pattern capture");
+}
+
+
+static const char *classend (MatchState *ms, const char *p) {
+  switch (*p++) {
+    case L_ESC: {
+      if (*p == '\0')
+        luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
+      return p+1;
+    }
+    case '[': {
+      if (*p == '^') p++;
+      do {  /* look for a `]' */
+        if (*p == '\0')
+          luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
+        if (*(p++) == L_ESC && *p != '\0')
+          p++;  /* skip escapes (e.g. `%]') */
+      } while (*p != ']');
+      return p+1;
+    }
+    default: {
+      return p;
+    }
+  }
+}
+
+
+static int match_class (int c, int cl) {
+  int res;
+  switch (tolower(cl)) {
+    case 'a' : res = isalpha(c); break;
+    case 'c' : res = iscntrl(c); break;
+    case 'd' : res = isdigit(c); break;
+    case 'l' : res = islower(c); break;
+    case 'p' : res = ispunct(c); break;
+    case 's' : res = isspace(c); break;
+    case 'u' : res = isupper(c); break;
+    case 'w' : res = isalnum(c); break;
+    case 'x' : res = isxdigit(c); break;
+    case 'z' : res = (c == 0); break;
+    default: return (cl == c);
+  }
+  return (islower(cl) ? res : !res);
+}
+
+
+static int matchbracketclass (int c, const char *p, const char *ec) {
+  int sig = 1;
+  if (*(p+1) == '^') {
+    sig = 0;
+    p++;  /* skip the `^' */
+  }
+  while (++p < ec) {
+    if (*p == L_ESC) {
+      p++;
+      if (match_class(c, uchar(*p)))
+        return sig;
+    }
+    else if ((*(p+1) == '-') && (p+2 < ec)) {
+      p+=2;
+      if (uchar(*(p-2)) <= c && c <= uchar(*p))
+        return sig;
+    }
+    else if (uchar(*p) == c) return sig;
+  }
+  return !sig;
+}
+
+
+static int singlematch (int c, const char *p, const char *ep) {
+  switch (*p) {
+    case '.': return 1;  /* matches any char */
+    case L_ESC: return match_class(c, uchar(*(p+1)));
+    case '[': return matchbracketclass(c, p, ep-1);
+    default:  return (uchar(*p) == c);
+  }
+}
+
+
+static const char *match (MatchState *ms, const char *s, const char *p);
+
+
+static const char *matchbalance (MatchState *ms, const char *s,
+                                   const char *p) {
+  if (*p == 0 || *(p+1) == 0)
+    luaL_error(ms->L, "unbalanced pattern");
+  if (*s != *p) return NULL;
+  else {
+    int b = *p;
+    int e = *(p+1);
+    int cont = 1;
+    while (++s < ms->src_end) {
+      if (*s == e) {
+        if (--cont == 0) return s+1;
+      }
+      else if (*s == b) cont++;
+    }
+  }
+  return NULL;  /* string ends out of balance */
+}
+
+
+static const char *max_expand (MatchState *ms, const char *s,
+                                 const char *p, const char *ep) {
+  ptrdiff_t i = 0;  /* counts maximum expand for item */
+  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
+    i++;
+  /* keeps trying to match with the maximum repetitions */
+  while (i>=0) {
+    const char *res = match(ms, (s+i), ep+1);
+    if (res) return res;
+    i--;  /* else didn't match; reduce 1 repetition to try again */
+  }
+  return NULL;
+}
+
+
+static const char *min_expand (MatchState *ms, const char *s,
+                                 const char *p, const char *ep) {
+  for (;;) {
+    const char *res = match(ms, s, ep+1);
+    if (res != NULL)
+      return res;
+    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
+      s++;  /* try with one more repetition */
+    else return NULL;
+  }
+}
+
+
+static const char *start_capture (MatchState *ms, const char *s,
+                                    const char *p, int what) {
+  const char *res;
+  int level = ms->level;
+  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
+  ms->capture[level].init = s;
+  ms->capture[level].len = what;
+  ms->level = level+1;
+  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
+    ms->level--;  /* undo capture */
+  return res;
+}
+
+
+static const char *end_capture (MatchState *ms, const char *s,
+                                  const char *p) {
+  int l = capture_to_close(ms);
+  const char *res;
+  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
+  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
+    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
+  return res;
+}
+
+
+static const char *match_capture (MatchState *ms, const char *s, int l) {
+  size_t len;
+  l = check_capture(ms, l);
+  len = ms->capture[l].len;
+  if ((size_t)(ms->src_end-s) >= len &&
+      memcmp(ms->capture[l].init, s, len) == 0)
+    return s+len;
+  else return NULL;
+}
+
+
+static const char *match (MatchState *ms, const char *s, const char *p) {
+  init: /* using goto's to optimize tail recursion */
+  switch (*p) {
+    case '(': {  /* start capture */
+      if (*(p+1) == ')')  /* position capture? */
+        return start_capture(ms, s, p+2, CAP_POSITION);
+      else
+        return start_capture(ms, s, p+1, CAP_UNFINISHED);
+    }
+    case ')': {  /* end capture */
+      return end_capture(ms, s, p+1);
+    }
+    case L_ESC: {
+      switch (*(p+1)) {
+        case 'b': {  /* balanced string? */
+          s = matchbalance(ms, s, p+2);
+          if (s == NULL) return NULL;
+          p+=4; goto init;  /* else return match(ms, s, p+4); */
+        }
+        case 'f': {  /* frontier? */
+          const char *ep; char previous;
+          p += 2;
+          if (*p != '[')
+            luaL_error(ms->L, "missing " LUA_QL("[") " after "
+                               LUA_QL("%%f") " in pattern");
+          ep = classend(ms, p);  /* points to what is next */
+          previous = (s == ms->src_init) ? '\0' : *(s-1);
+          if (matchbracketclass(uchar(previous), p, ep-1) ||
+             !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
+          p=ep; goto init;  /* else return match(ms, s, ep); */
+        }
+        default: {
+          if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
+            s = match_capture(ms, s, uchar(*(p+1)));
+            if (s == NULL) return NULL;
+            p+=2; goto init;  /* else return match(ms, s, p+2) */
+          }
+          goto dflt;  /* case default */
+        }
+      }
+    }
+    case '\0': {  /* end of pattern */
+      return s;  /* match succeeded */
+    }
+    case '$': {
+      if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */
+        return (s == ms->src_end) ? s : NULL;  /* check end of string */
+      else goto dflt;
+    }
+    default: dflt: {  /* it is a pattern item */
+      const char *ep = classend(ms, p);  /* points to what is next */
+      int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
+      switch (*ep) {
+        case '?': {  /* optional */
+          const char *res;
+          if (m && ((res=match(ms, s+1, ep+1)) != NULL))
+            return res;
+          p=ep+1; goto init;  /* else return match(ms, s, ep+1); */
+        }
+        case '*': {  /* 0 or more repetitions */
+          return max_expand(ms, s, p, ep);
+        }
+        case '+': {  /* 1 or more repetitions */
+          return (m ? max_expand(ms, s+1, p, ep) : NULL);
+        }
+        case '-': {  /* 0 or more repetitions (minimum) */
+          return min_expand(ms, s, p, ep);
+        }
+        default: {
+          if (!m) return NULL;
+          s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */
+        }
+      }
+    }
+  }
+}
+
+
+
+static const char *lmemfind (const char *s1, size_t l1,
+                               const char *s2, size_t l2) {
+  if (l2 == 0) return s1;  /* empty strings are everywhere */
+  else if (l2 > l1) return NULL;  /* avoids a negative `l1' */
+  else {
+    const char *init;  /* to search for a `*s2' inside `s1' */
+    l2--;  /* 1st char will be checked by `memchr' */
+    l1 = l1-l2;  /* `s2' cannot be found after that */
+    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
+      init++;   /* 1st char is already checked */
+      if (memcmp(init, s2+1, l2) == 0)
+        return init-1;
+      else {  /* correct `l1' and `s1' to try again */
+        l1 -= init-s1;
+        s1 = init;
+      }
+    }
+    return NULL;  /* not found */
+  }
+}
+
+
+static void push_onecapture (MatchState *ms, int i, const char *s,
+                                                    const char *e) {
+  if (i >= ms->level) {
+    if (i == 0)  /* ms->level == 0, too */
+      lua_pushlstring(ms->L, s, e - s);  /* add whole match */
+    else
+      luaL_error(ms->L, "invalid capture index");
+  }
+  else {
+    ptrdiff_t l = ms->capture[i].len;
+    if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
+    if (l == CAP_POSITION)
+      lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
+    else
+      lua_pushlstring(ms->L, ms->capture[i].init, l);
+  }
+}
+
+
+static int push_captures (MatchState *ms, const char *s, const char *e) {
+  int i;
+  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
+  luaL_checkstack(ms->L, nlevels, "too many captures");
+  for (i = 0; i < nlevels; i++)
+    push_onecapture(ms, i, s, e);
+  return nlevels;  /* number of strings pushed */
+}
+
+
+static int str_find_aux (lua_State *L, int find) {
+  size_t l1, l2;
+  const char *s = luaL_checklstring(L, 1, &l1);
+  const char *p = luaL_checklstring(L, 2, &l2);
+  ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
+  if (init < 0) init = 0;
+  else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
+  if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
+      strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */
+    /* do a plain search */
+    const char *s2 = lmemfind(s+init, l1-init, p, l2);
+    if (s2) {
+      lua_pushinteger(L, s2-s+1);
+      lua_pushinteger(L, s2-s+l2);
+      return 2;
+    }
+  }
+  else {
+    MatchState ms;
+    int anchor = (*p == '^') ? (p++, 1) : 0;
+    const char *s1=s+init;
+    ms.L = L;
+    ms.src_init = s;
+    ms.src_end = s+l1;
+    do {
+      const char *res;
+      ms.level = 0;
+      if ((res=match(&ms, s1, p)) != NULL) {
+        if (find) {
+          lua_pushinteger(L, s1-s+1);  /* start */
+          lua_pushinteger(L, res-s);   /* end */
+          return push_captures(&ms, NULL, 0) + 2;
+        }
+        else
+          return push_captures(&ms, s1, res);
+      }
+    } while (s1++ < ms.src_end && !anchor);
+  }
+  lua_pushnil(L);  /* not found */
+  return 1;
+}
+
+
+static int str_find (lua_State *L) {
+  return str_find_aux(L, 1);
+}
+
+
+static int str_match (lua_State *L) {
+  return str_find_aux(L, 0);
+}
+
+
+static int gmatch_aux (lua_State *L) {
+  MatchState ms;
+  size_t ls;
+  const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+  const char *p = lua_tostring(L, lua_upvalueindex(2));
+  const char *src;
+  ms.L = L;
+  ms.src_init = s;
+  ms.src_end = s+ls;
+  for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
+       src <= ms.src_end;
+       src++) {
+    const char *e;
+    ms.level = 0;
+    if ((e = match(&ms, src, p)) != NULL) {
+      lua_Integer newstart = e-s;
+      if (e == src) newstart++;  /* empty match? go at least one position */
+      lua_pushinteger(L, newstart);
+      lua_replace(L, lua_upvalueindex(3));
+      return push_captures(&ms, src, e);
+    }
+  }
+  return 0;  /* not found */
+}
+
+
+static int gmatch (lua_State *L) {
+  luaL_checkstring(L, 1);
+  luaL_checkstring(L, 2);
+  lua_settop(L, 2);
+  lua_pushinteger(L, 0);
+  lua_pushcclosure(L, gmatch_aux, 3);
+  return 1;
+}
+
+
+static int gfind_nodef (lua_State *L) {
+  return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
+                       LUA_QL("string.gmatch"));
+}
+
+
+static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
+                                                   const char *e) {
+  size_t l, i;
+  const char *news = lua_tolstring(ms->L, 3, &l);
+  for (i = 0; i < l; i++) {
+    if (news[i] != L_ESC)
+      luaL_addchar(b, news[i]);
+    else {
+      i++;  /* skip ESC */
+      if (!isdigit(uchar(news[i])))
+        luaL_addchar(b, news[i]);
+      else if (news[i] == '0')
+          luaL_addlstring(b, s, e - s);
+      else {
+        push_onecapture(ms, news[i] - '1', s, e);
+        luaL_addvalue(b);  /* add capture to accumulated result */
+      }
+    }
+  }
+}
+
+
+static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
+                                                       const char *e) {
+  lua_State *L = ms->L;
+  switch (lua_type(L, 3)) {
+    case LUA_TNUMBER:
+    case LUA_TSTRING: {
+      add_s(ms, b, s, e);
+      return;
+    }
+    case LUA_TFUNCTION: {
+      int n;
+      lua_pushvalue(L, 3);
+      n = push_captures(ms, s, e);
+      lua_call(L, n, 1);
+      break;
+    }
+    case LUA_TTABLE: {
+      push_onecapture(ms, 0, s, e);
+      lua_gettable(L, 3);
+      break;
+    }
+  }
+  if (!lua_toboolean(L, -1)) {  /* nil or false? */
+    lua_pop(L, 1);
+    lua_pushlstring(L, s, e - s);  /* keep original text */
+  }
+  else if (!lua_isstring(L, -1))
+    luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); 
+  luaL_addvalue(b);  /* add result to accumulator */
+}
+
+
+static int str_gsub (lua_State *L) {
+  size_t srcl;
+  const char *src = luaL_checklstring(L, 1, &srcl);
+  const char *p = luaL_checkstring(L, 2);
+  int  tr = lua_type(L, 3);
+  int max_s = luaL_optint(L, 4, srcl+1);
+  int anchor = (*p == '^') ? (p++, 1) : 0;
+  int n = 0;
+  MatchState ms;
+  luaL_Buffer b;
+  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
+                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
+                      "string/function/table expected");
+  luaL_buffinit(L, &b);
+  ms.L = L;
+  ms.src_init = src;
+  ms.src_end = src+srcl;
+  while (n < max_s) {
+    const char *e;
+    ms.level = 0;
+    e = match(&ms, src, p);
+    if (e) {
+      n++;
+      add_value(&ms, &b, src, e);
+    }
+    if (e && e>src) /* non empty match? */
+      src = e;  /* skip it */
+    else if (src < ms.src_end)
+      luaL_addchar(&b, *src++);
+    else break;
+    if (anchor) break;
+  }
+  luaL_addlstring(&b, src, ms.src_end-src);
+  luaL_pushresult(&b);
+  lua_pushinteger(L, n);  /* number of substitutions */
+  return 2;
+}
+
+/* }====================================================== */
+
+
+/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
+#define MAX_ITEM	512
+/* valid flags in a format specification */
+#define FLAGS	"-+ #0"
+/*
+** maximum size of each format specification (such as '%-099.99d')
+** (+10 accounts for %99.99x plus margin of error)
+*/
+#define MAX_FORMAT	(sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
+
+
+static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
+  size_t l;
+  const char *s = luaL_checklstring(L, arg, &l);
+  luaL_addchar(b, '"');
+  while (l--) {
+    switch (*s) {
+      case '"': case '\\': case '\n': {
+        luaL_addchar(b, '\\');
+        luaL_addchar(b, *s);
+        break;
+      }
+      case '\r': {
+        luaL_addlstring(b, "\\r", 2);
+        break;
+      }
+      case '\0': {
+        luaL_addlstring(b, "\\000", 4);
+        break;
+      }
+      default: {
+        luaL_addchar(b, *s);
+        break;
+      }
+    }
+    s++;
+  }
+  luaL_addchar(b, '"');
+}
+
+static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
+  const char *p = strfrmt;
+  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
+  if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
+    luaL_error(L, "invalid format (repeated flags)");
+  if (isdigit(uchar(*p))) p++;  /* skip width */
+  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
+  if (*p == '.') {
+    p++;
+    if (isdigit(uchar(*p))) p++;  /* skip precision */
+    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
+  }
+  if (isdigit(uchar(*p)))
+    luaL_error(L, "invalid format (width or precision too long)");
+  *(form++) = '%';
+  strncpy(form, strfrmt, p - strfrmt + 1);
+  form += p - strfrmt + 1;
+  *form = '\0';
+  return p;
+}
+
+
+static void addintlen (char *form) {
+  size_t l = strlen(form);
+  char spec = form[l - 1];
+  strcpy(form + l - 1, LUA_INTFRMLEN);
+  form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
+  form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
+}
+
+
+static int str_format (lua_State *L) {
+  int arg = 1;
+  size_t sfl;
+  const char *strfrmt = luaL_checklstring(L, arg, &sfl);
+  const char *strfrmt_end = strfrmt+sfl;
+  luaL_Buffer b;
+  luaL_buffinit(L, &b);
+  while (strfrmt < strfrmt_end) {
+    if (*strfrmt != L_ESC)
+      luaL_addchar(&b, *strfrmt++);
+    else if (*++strfrmt == L_ESC)
+      luaL_addchar(&b, *strfrmt++);  /* %% */
+    else { /* format item */
+      char form[MAX_FORMAT];  /* to store the format (`%...') */
+      char buff[MAX_ITEM];  /* to store the formatted item */
+      arg++;
+      strfrmt = scanformat(L, strfrmt, form);
+      switch (*strfrmt++) {
+        case 'c': {
+          sprintf(buff, form, (int)luaL_checknumber(L, arg));
+          break;
+        }
+        case 'd':  case 'i': {
+          addintlen(form);
+          sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg));
+          break;
+        }
+        case 'o':  case 'u':  case 'x':  case 'X': {
+          addintlen(form);
+          sprintf(buff, form, (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
+          break;
+        }
+#if !defined LUA_NUMBER_INTEGRAL
+        case 'e':  case 'E': case 'f':
+        case 'g': case 'G': {
+          sprintf(buff, form, (double)luaL_checknumber(L, arg));
+          break;
+        }
+#endif
+        case 'q': {
+          addquoted(L, &b, arg);
+          continue;  /* skip the 'addsize' at the end */
+        }
+        case 's': {
+          size_t l;
+          const char *s = luaL_checklstring(L, arg, &l);
+          if (!strchr(form, '.') && l >= 100) {
+            /* no precision and string is too long to be formatted;
+               keep original string */
+            lua_pushvalue(L, arg);
+            luaL_addvalue(&b);
+            continue;  /* skip the `addsize' at the end */
+          }
+          else {
+            sprintf(buff, form, s);
+            break;
+          }
+        }
+        default: {  /* also treat cases `pnLlh' */
+          return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
+                               LUA_QL("format"), *(strfrmt - 1));
+        }
+      }
+      luaL_addlstring(&b, buff, strlen(buff));
+    }
+  }
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static const luaL_Reg strlib[] = {
+  {"byte", str_byte},
+  {"char", str_char},
+  {"dump", str_dump},
+  {"find", str_find},
+  {"format", str_format},
+  {"gfind", gfind_nodef},
+  {"gmatch", gmatch},
+  {"gsub", str_gsub},
+  {"len", str_len},
+  {"lower", str_lower},
+  {"match", str_match},
+  {"rep", str_rep},
+  {"reverse", str_reverse},
+  {"sub", str_sub},
+  {"upper", str_upper},
+  {NULL, NULL}
+};
+
+
+static void createmetatable (lua_State *L) {
+  lua_createtable(L, 0, 1);  /* create metatable for strings */
+  lua_pushliteral(L, "");  /* dummy string */
+  lua_pushvalue(L, -2);
+  lua_setmetatable(L, -2);  /* set string metatable */
+  lua_pop(L, 1);  /* pop dummy string */
+  lua_pushvalue(L, -2);  /* string library... */
+  lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */
+  lua_pop(L, 1);  /* pop metatable */
+}
+
+
+/*
+** Open string library
+*/
+LUALIB_API int luaopen_string (lua_State *L) {
+  luaL_register(L, LUA_STRLIBNAME, strlib);
+#if defined(LUA_COMPAT_GFIND)
+  lua_getfield(L, -1, "gmatch");
+  lua_setfield(L, -2, "gfind");
+#endif
+  createmetatable(L);
+  return 1;
+}
+

=== added file 'lua/ltable.c'
--- lua/ltable.c	1970-01-01 00:00:00 +0000
+++ lua/ltable.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,590 @@
+/*
+** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+
+/*
+** Implementation of tables (aka arrays, objects, or hash tables).
+** Tables keep its elements in two parts: an array part and a hash part.
+** Non-negative integer keys are all candidates to be kept in the array
+** part. The actual size of the array is the largest `n' such that at
+** least half the slots between 0 and n are in use.
+** Hash uses a mix of chained scatter table with Brent's variation.
+** A main invariant of these tables is that, if an element is not
+** in its main position (i.e. the `original' position that its hash gives
+** to it), then the colliding element is in its own main position.
+** Hence even when the load factor reaches 100%, performance remains good.
+*/
+
+#ifndef USE_GRUB_LIB
+#include <math.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define ltable_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstate.h"
+#include "ltable.h"
+
+
+/*
+** max size of array part is 2^MAXBITS
+*/
+#if LUAI_BITSINT > 26
+#define MAXBITS		26
+#else
+#define MAXBITS		(LUAI_BITSINT-2)
+#endif
+
+#define MAXASIZE	(1 << MAXBITS)
+
+
+#define hashpow2(t,n)      (gnode(t, lmod((n), sizenode(t))))
+  
+#define hashstr(t,str)  hashpow2(t, (str)->tsv.hash)
+#define hashboolean(t,p)        hashpow2(t, p)
+
+
+/*
+** for some types, it is better to avoid modulus by power of 2, as
+** they tend to have many 2 factors.
+*/
+#define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))
+
+
+#define hashpointer(t,p)	hashmod(t, IntPoint(p))
+
+
+/*
+** number of ints inside a lua_Number
+*/
+#define numints		cast_int(sizeof(lua_Number)/sizeof(int))
+
+
+
+#define dummynode		(&dummynode_)
+
+static const Node dummynode_ = {
+  {{NULL}, LUA_TNIL},  /* value */
+  {{{NULL}, LUA_TNIL, NULL}}  /* key */
+};
+
+
+/*
+** hash for lua_Numbers
+*/
+static Node *hashnum (const Table *t, lua_Number n) {
+  unsigned int a[numints];
+  int i;
+  if (luai_numeq(n, 0))  /* avoid problems with -0 */
+    return gnode(t, 0);
+  memcpy(a, &n, sizeof(a));
+  for (i = 1; i < numints; i++) a[0] += a[i];
+  return hashmod(t, a[0]);
+}
+
+
+
+/*
+** returns the `main' position of an element in a table (that is, the index
+** of its hash value)
+*/
+static Node *mainposition (const Table *t, const TValue *key) {
+  switch (ttype(key)) {
+    case LUA_TNUMBER:
+      return hashnum(t, nvalue(key));
+    case LUA_TSTRING:
+      return hashstr(t, rawtsvalue(key));
+    case LUA_TBOOLEAN:
+      return hashboolean(t, bvalue(key));
+    case LUA_TLIGHTUSERDATA:
+      return hashpointer(t, pvalue(key));
+    default:
+      return hashpointer(t, gcvalue(key));
+  }
+}
+
+
+/*
+** returns the index for `key' if `key' is an appropriate key to live in
+** the array part of the table, -1 otherwise.
+*/
+static int arrayindex (const TValue *key) {
+  if (ttisnumber(key)) {
+    lua_Number n = nvalue(key);
+    int k;
+    lua_number2int(k, n);
+    if (luai_numeq(cast_num(k), n))
+      return k;
+  }
+  return -1;  /* `key' did not match some condition */
+}
+
+
+/*
+** returns the index of a `key' for table traversals. First goes all
+** elements in the array part, then elements in the hash part. The
+** beginning of a traversal is signalled by -1.
+*/
+static int findindex (lua_State *L, Table *t, StkId key) {
+  int i;
+  if (ttisnil(key)) return -1;  /* first iteration */
+  i = arrayindex(key);
+  if (0 < i && i <= t->sizearray)  /* is `key' inside array part? */
+    return i-1;  /* yes; that's the index (corrected to C) */
+  else {
+    Node *n = mainposition(t, key);
+    do {  /* check whether `key' is somewhere in the chain */
+      /* key may be dead already, but it is ok to use it in `next' */
+      if (luaO_rawequalObj(key2tval(n), key) ||
+            (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
+             gcvalue(gkey(n)) == gcvalue(key))) {
+        i = cast_int(n - gnode(t, 0));  /* key index in hash table */
+        /* hash elements are numbered after array ones */
+        return i + t->sizearray;
+      }
+      else n = gnext(n);
+    } while (n);
+    luaG_runerror(L, "invalid key to " LUA_QL("next"));  /* key not found */
+    return 0;  /* to avoid warnings */
+  }
+}
+
+
+int luaH_next (lua_State *L, Table *t, StkId key) {
+  int i = findindex(L, t, key);  /* find original element */
+  for (i++; i < t->sizearray; i++) {  /* try first array part */
+    if (!ttisnil(&t->array[i])) {  /* a non-nil value? */
+      setnvalue(key, cast_num(i+1));
+      setobj2s(L, key+1, &t->array[i]);
+      return 1;
+    }
+  }
+  for (i -= t->sizearray; i < sizenode(t); i++) {  /* then hash part */
+    if (!ttisnil(gval(gnode(t, i)))) {  /* a non-nil value? */
+      setobj2s(L, key, key2tval(gnode(t, i)));
+      setobj2s(L, key+1, gval(gnode(t, i)));
+      return 1;
+    }
+  }
+  return 0;  /* no more elements */
+}
+
+
+/*
+** {=============================================================
+** Rehash
+** ==============================================================
+*/
+
+
+static int computesizes (int nums[], int *narray) {
+  int i;
+  int twotoi;  /* 2^i */
+  int a = 0;  /* number of elements smaller than 2^i */
+  int na = 0;  /* number of elements to go to array part */
+  int n = 0;  /* optimal size for array part */
+  for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
+    if (nums[i] > 0) {
+      a += nums[i];
+      if (a > twotoi/2) {  /* more than half elements present? */
+        n = twotoi;  /* optimal size (till now) */
+        na = a;  /* all elements smaller than n will go to array part */
+      }
+    }
+    if (a == *narray) break;  /* all elements already counted */
+  }
+  *narray = n;
+  lua_assert(*narray/2 <= na && na <= *narray);
+  return na;
+}
+
+
+static int countint (const TValue *key, int *nums) {
+  int k = arrayindex(key);
+  if (0 < k && k <= MAXASIZE) {  /* is `key' an appropriate array index? */
+    nums[ceillog2(k)]++;  /* count as such */
+    return 1;
+  }
+  else
+    return 0;
+}
+
+
+static int numusearray (const Table *t, int *nums) {
+  int lg;
+  int ttlg;  /* 2^lg */
+  int ause = 0;  /* summation of `nums' */
+  int i = 1;  /* count to traverse all array keys */
+  for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) {  /* for each slice */
+    int lc = 0;  /* counter */
+    int lim = ttlg;
+    if (lim > t->sizearray) {
+      lim = t->sizearray;  /* adjust upper limit */
+      if (i > lim)
+        break;  /* no more elements to count */
+    }
+    /* count elements in range (2^(lg-1), 2^lg] */
+    for (; i <= lim; i++) {
+      if (!ttisnil(&t->array[i-1]))
+        lc++;
+    }
+    nums[lg] += lc;
+    ause += lc;
+  }
+  return ause;
+}
+
+
+static int numusehash (const Table *t, int *nums, int *pnasize) {
+  int totaluse = 0;  /* total number of elements */
+  int ause = 0;  /* summation of `nums' */
+  int i = sizenode(t);
+  while (i--) {
+    Node *n = &t->node[i];
+    if (!ttisnil(gval(n))) {
+      ause += countint(key2tval(n), nums);
+      totaluse++;
+    }
+  }
+  *pnasize += ause;
+  return totaluse;
+}
+
+
+static void setarrayvector (lua_State *L, Table *t, int size) {
+  int i;
+  luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
+  for (i=t->sizearray; i<size; i++)
+     setnilvalue(&t->array[i]);
+  t->sizearray = size;
+}
+
+
+static void setnodevector (lua_State *L, Table *t, int size) {
+  int lsize;
+  if (size == 0) {  /* no elements to hash part? */
+    t->node = cast(Node *, dummynode);  /* use common `dummynode' */
+    lsize = 0;
+  }
+  else {
+    int i;
+    lsize = ceillog2(size);
+    if (lsize > MAXBITS)
+      luaG_runerror(L, "table overflow");
+    size = twoto(lsize);
+    t->node = luaM_newvector(L, size, Node);
+    for (i=0; i<size; i++) {
+      Node *n = gnode(t, i);
+      gnext(n) = NULL;
+      setnilvalue(gkey(n));
+      setnilvalue(gval(n));
+    }
+  }
+  t->lsizenode = cast_byte(lsize);
+  t->lastfree = gnode(t, size);  /* all positions are free */
+}
+
+
+static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
+  int i;
+  int oldasize = t->sizearray;
+  int oldhsize = t->lsizenode;
+  Node *nold = t->node;  /* save old hash ... */
+  if (nasize > oldasize)  /* array part must grow? */
+    setarrayvector(L, t, nasize);
+  /* create new hash part with appropriate size */
+  setnodevector(L, t, nhsize);  
+  if (nasize < oldasize) {  /* array part must shrink? */
+    t->sizearray = nasize;
+    /* re-insert elements from vanishing slice */
+    for (i=nasize; i<oldasize; i++) {
+      if (!ttisnil(&t->array[i]))
+        setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
+    }
+    /* shrink array */
+    luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
+  }
+  /* re-insert elements from hash part */
+  for (i = twoto(oldhsize) - 1; i >= 0; i--) {
+    Node *old = nold+i;
+    if (!ttisnil(gval(old)))
+      setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old));
+  }
+  if (nold != dummynode)
+    luaM_freearray(L, nold, twoto(oldhsize), Node);  /* free old array */
+}
+
+
+void luaH_resizearray (lua_State *L, Table *t, int nasize) {
+  int nsize = (t->node == dummynode) ? 0 : sizenode(t);
+  resize(L, t, nasize, nsize);
+}
+
+
+static void rehash (lua_State *L, Table *t, const TValue *ek) {
+  int nasize, na;
+  int nums[MAXBITS+1];  /* nums[i] = number of keys between 2^(i-1) and 2^i */
+  int i;
+  int totaluse;
+  for (i=0; i<=MAXBITS; i++) nums[i] = 0;  /* reset counts */
+  nasize = numusearray(t, nums);  /* count keys in array part */
+  totaluse = nasize;  /* all those keys are integer keys */
+  totaluse += numusehash(t, nums, &nasize);  /* count keys in hash part */
+  /* count extra key */
+  nasize += countint(ek, nums);
+  totaluse++;
+  /* compute new size for array part */
+  na = computesizes(nums, &nasize);
+  /* resize the table to new computed sizes */
+  resize(L, t, nasize, totaluse - na);
+}
+
+
+
+/*
+** }=============================================================
+*/
+
+
+Table *luaH_new (lua_State *L, int narray, int nhash) {
+  Table *t = luaM_new(L, Table);
+  luaC_link(L, obj2gco(t), LUA_TTABLE);
+  t->metatable = NULL;
+  t->flags = cast_byte(~0);
+  /* temporary values (kept only if some malloc fails) */
+  t->array = NULL;
+  t->sizearray = 0;
+  t->lsizenode = 0;
+  t->node = cast(Node *, dummynode);
+  setarrayvector(L, t, narray);
+  setnodevector(L, t, nhash);
+  return t;
+}
+
+
+void luaH_free (lua_State *L, Table *t) {
+  if (t->node != dummynode)
+    luaM_freearray(L, t->node, sizenode(t), Node);
+  luaM_freearray(L, t->array, t->sizearray, TValue);
+  luaM_free(L, t);
+}
+
+
+static Node *getfreepos (Table *t) {
+  while (t->lastfree-- > t->node) {
+    if (ttisnil(gkey(t->lastfree)))
+      return t->lastfree;
+  }
+  return NULL;  /* could not find a free place */
+}
+
+
+
+/*
+** inserts a new key into a hash table; first, check whether key's main 
+** position is free. If not, check whether colliding node is in its main 
+** position or not: if it is not, move colliding node to an empty place and 
+** put new key in its main position; otherwise (colliding node is in its main 
+** position), new key goes to an empty position. 
+*/
+static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
+  Node *mp = mainposition(t, key);
+  if (!ttisnil(gval(mp)) || mp == dummynode) {
+    Node *othern;
+    Node *n = getfreepos(t);  /* get a free place */
+    if (n == NULL) {  /* cannot find a free place? */
+      rehash(L, t, key);  /* grow table */
+      return luaH_set(L, t, key);  /* re-insert key into grown table */
+    }
+    lua_assert(n != dummynode);
+    othern = mainposition(t, key2tval(mp));
+    if (othern != mp) {  /* is colliding node out of its main position? */
+      /* yes; move colliding node into free position */
+      while (gnext(othern) != mp) othern = gnext(othern);  /* find previous */
+      gnext(othern) = n;  /* redo the chain with `n' in place of `mp' */
+      *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
+      gnext(mp) = NULL;  /* now `mp' is free */
+      setnilvalue(gval(mp));
+    }
+    else {  /* colliding node is in its own main position */
+      /* new node will go into free position */
+      gnext(n) = gnext(mp);  /* chain new position */
+      gnext(mp) = n;
+      mp = n;
+    }
+  }
+  gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
+  luaC_barriert(L, t, key);
+  lua_assert(ttisnil(gval(mp)));
+  return gval(mp);
+}
+
+
+/*
+** search function for integers
+*/
+const TValue *luaH_getnum (Table *t, int key) {
+  /* (1 <= key && key <= t->sizearray) */
+  if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray))
+    return &t->array[key-1];
+  else {
+    lua_Number nk = cast_num(key);
+    Node *n = hashnum(t, nk);
+    do {  /* check whether `key' is somewhere in the chain */
+      if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk))
+        return gval(n);  /* that's it */
+      else n = gnext(n);
+    } while (n);
+    return luaO_nilobject;
+  }
+}
+
+
+/*
+** search function for strings
+*/
+const TValue *luaH_getstr (Table *t, TString *key) {
+  Node *n = hashstr(t, key);
+  do {  /* check whether `key' is somewhere in the chain */
+    if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
+      return gval(n);  /* that's it */
+    else n = gnext(n);
+  } while (n);
+  return luaO_nilobject;
+}
+
+
+/*
+** main search function
+*/
+const TValue *luaH_get (Table *t, const TValue *key) {
+  switch (ttype(key)) {
+    case LUA_TNIL: return luaO_nilobject;
+    case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
+    case LUA_TNUMBER: {
+      int k;
+      lua_Number n = nvalue(key);
+      lua_number2int(k, n);
+      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
+        return luaH_getnum(t, k);  /* use specialized version */
+      /* else go through */
+    }
+    default: {
+      Node *n = mainposition(t, key);
+      do {  /* check whether `key' is somewhere in the chain */
+        if (luaO_rawequalObj(key2tval(n), key))
+          return gval(n);  /* that's it */
+        else n = gnext(n);
+      } while (n);
+      return luaO_nilobject;
+    }
+  }
+}
+
+
+TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
+  const TValue *p = luaH_get(t, key);
+  t->flags = 0;
+  if (p != luaO_nilobject)
+    return cast(TValue *, p);
+  else {
+    if (ttisnil(key)) luaG_runerror(L, "table index is nil");
+    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
+      luaG_runerror(L, "table index is NaN");
+    return newkey(L, t, key);
+  }
+}
+
+
+TValue *luaH_setnum (lua_State *L, Table *t, int key) {
+  const TValue *p = luaH_getnum(t, key);
+  if (p != luaO_nilobject)
+    return cast(TValue *, p);
+  else {
+    TValue k;
+    setnvalue(&k, cast_num(key));
+    return newkey(L, t, &k);
+  }
+}
+
+
+TValue *luaH_setstr (lua_State *L, Table *t, TString *key) {
+  const TValue *p = luaH_getstr(t, key);
+  if (p != luaO_nilobject)
+    return cast(TValue *, p);
+  else {
+    TValue k;
+    setsvalue(L, &k, key);
+    return newkey(L, t, &k);
+  }
+}
+
+
+static int unbound_search (Table *t, unsigned int j) {
+  unsigned int i = j;  /* i is zero or a present index */
+  j++;
+  /* find `i' and `j' such that i is present and j is not */
+  while (!ttisnil(luaH_getnum(t, j))) {
+    i = j;
+    j *= 2;
+    if (j > cast(unsigned int, MAX_INT)) {  /* overflow? */
+      /* table was built with bad purposes: resort to linear search */
+      i = 1;
+      while (!ttisnil(luaH_getnum(t, i))) i++;
+      return i - 1;
+    }
+  }
+  /* now do a binary search between them */
+  while (j - i > 1) {
+    unsigned int m = (i+j)/2;
+    if (ttisnil(luaH_getnum(t, m))) j = m;
+    else i = m;
+  }
+  return i;
+}
+
+
+/*
+** Try to find a boundary in table `t'. A `boundary' is an integer index
+** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
+*/
+int luaH_getn (Table *t) {
+  unsigned int j = t->sizearray;
+  if (j > 0 && ttisnil(&t->array[j - 1])) {
+    /* there is a boundary in the array part: (binary) search for it */
+    unsigned int i = 0;
+    while (j - i > 1) {
+      unsigned int m = (i+j)/2;
+      if (ttisnil(&t->array[m - 1])) j = m;
+      else i = m;
+    }
+    return i;
+  }
+  /* else must find a boundary in hash part */
+  else if (t->node == dummynode)  /* hash part is empty? */
+    return j;  /* that is easy... */
+  else return unbound_search(t, j);
+}
+
+
+
+#if defined(LUA_DEBUG)
+
+Node *luaH_mainposition (const Table *t, const TValue *key) {
+  return mainposition(t, key);
+}
+
+int luaH_isdummy (Node *n) { return n == dummynode; }
+
+#endif

=== added file 'lua/ltable.h'
--- lua/ltable.h	1970-01-01 00:00:00 +0000
+++ lua/ltable.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,40 @@
+/*
+** $Id: ltable.h,v 2.10.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lua tables (hash)
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltable_h
+#define ltable_h
+
+#include "lobject.h"
+
+
+#define gnode(t,i)	(&(t)->node[i])
+#define gkey(n)		(&(n)->i_key.nk)
+#define gval(n)		(&(n)->i_val)
+#define gnext(n)	((n)->i_key.nk.next)
+
+#define key2tval(n)	(&(n)->i_key.tvk)
+
+
+LUAI_FUNC const TValue *luaH_getnum (Table *t, int key);
+LUAI_FUNC TValue *luaH_setnum (lua_State *L, Table *t, int key);
+LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
+LUAI_FUNC TValue *luaH_setstr (lua_State *L, Table *t, TString *key);
+LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
+LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
+LUAI_FUNC Table *luaH_new (lua_State *L, int narray, int lnhash);
+LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
+LUAI_FUNC void luaH_free (lua_State *L, Table *t);
+LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
+LUAI_FUNC int luaH_getn (Table *t);
+
+
+#if defined(LUA_DEBUG)
+LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
+LUAI_FUNC int luaH_isdummy (Node *n);
+#endif
+
+
+#endif

=== added file 'lua/ltablib.c'
--- lua/ltablib.c	1970-01-01 00:00:00 +0000
+++ lua/ltablib.c	2008-08-01 15:19:23 +0000
@@ -0,0 +1,279 @@
+/*
+** $Id: ltablib.c,v 1.38.1.2 2007/12/28 15:32:23 roberto Exp $
+** Library for Table Manipulation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <stddef.h>
+
+#define ltablib_c
+#define LUA_LIB
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+#define aux_getn(L,n)	(luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
+
+
+static int foreachi (lua_State *L) {
+  int i;
+  int n = aux_getn(L, 1);
+  luaL_checktype(L, 2, LUA_TFUNCTION);
+  for (i=1; i <= n; i++) {
+    lua_pushvalue(L, 2);  /* function */
+    lua_pushinteger(L, i);  /* 1st argument */
+    lua_rawgeti(L, 1, i);  /* 2nd argument */
+    lua_call(L, 2, 1);
+    if (!lua_isnil(L, -1))
+      return 1;
+    lua_pop(L, 1);  /* remove nil result */
+  }
+  return 0;
+}
+
+
+static int foreach (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checktype(L, 2, LUA_TFUNCTION);
+  lua_pushnil(L);  /* first key */
+  while (lua_next(L, 1)) {
+    lua_pushvalue(L, 2);  /* function */
+    lua_pushvalue(L, -3);  /* key */
+    lua_pushvalue(L, -3);  /* value */
+    lua_call(L, 2, 1);
+    if (!lua_isnil(L, -1))
+      return 1;
+    lua_pop(L, 2);  /* remove value and result */
+  }
+  return 0;
+}
+
+
+static int maxn (lua_State *L) {
+  lua_Number max = 0;
+  luaL_checktype(L, 1, LUA_TTABLE);
+  lua_pushnil(L);  /* first key */
+  while (lua_next(L, 1)) {
+    lua_pop(L, 1);  /* remove value */
+    if (lua_type(L, -1) == LUA_TNUMBER) {
+      lua_Number v = lua_tonumber(L, -1);
+      if (v > max) max = v;
+    }
+  }
+  lua_pushnumber(L, max);
+  return 1;
+}
+
+
+static int getn (lua_State *L) {
+  lua_pushinteger(L, aux_getn(L, 1));
+  return 1;
+}
+
+
+static int setn (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+#ifndef luaL_setn
+  luaL_setn(L, 1, luaL_checkint(L, 2));
+#else
+  luaL_error(L, LUA_QL("setn") " is obsolete");
+#endif
+  lua_pushvalue(L, 1);
+  return 1;
+}
+
+
+static int tinsert (lua_State *L) {
+  int e = aux_getn(L, 1) + 1;  /* first empty element */
+  int pos;  /* where to insert new element */
+  switch (lua_gettop(L)) {
+    case 2: {  /* called with only 2 arguments */
+      pos = e;  /* insert new element at the end */
+      break;
+    }
+    case 3: {
+      int i;
+      pos = luaL_checkint(L, 2);  /* 2nd argument is the position */
+      if (pos > e) e = pos;  /* `grow' array if necessary */
+      for (i = e; i > pos; i--) {  /* move up elements */
+        lua_rawgeti(L, 1, i-1);
+        lua_rawseti(L, 1, i);  /* t[i] = t[i-1] */
+      }
+      break;
+    }
+    default: {
+      return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
+    }
+  }
+  luaL_setn(L, 1, e);  /* new size */
+  lua_rawseti(L, 1, pos);  /* t[pos] = v */
+  return 0;
+}
+
+
+static int tremove (lua_State *L) {
+  int e = aux_getn(L, 1);
+  int pos = luaL_optint(L, 2, e);
+  if (!(1 <= pos && pos <= e))  /* position is outside bounds? */
+   return 0;  /* nothing to remove */
+  luaL_setn(L, 1, e - 1);  /* t.n = n-1 */
+  lua_rawgeti(L, 1, pos);  /* result = t[pos] */
+  for ( ;pos<e; pos++) {
+    lua_rawgeti(L, 1, pos+1);
+    lua_rawseti(L, 1, pos);  /* t[pos] = t[pos+1] */
+  }
+  lua_pushnil(L);
+  lua_rawseti(L, 1, e);  /* t[e] = nil */
+  return 1;
+}
+
+
+static int tconcat (lua_State *L) {
+  luaL_Buffer b;
+  size_t lsep;
+  int i, last;
+  const char *sep = luaL_optlstring(L, 2, "", &lsep);
+  luaL_checktype(L, 1, LUA_TTABLE);
+  i = luaL_optint(L, 3, 1);
+  last = luaL_opt(L, luaL_checkint, 4, luaL_getn(L, 1));
+  luaL_buffinit(L, &b);
+  for (; i <= last; i++) {
+    lua_rawgeti(L, 1, i);
+    luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings");
+    luaL_addvalue(&b);
+    if (i != last)
+      luaL_addlstring(&b, sep, lsep);
+  }
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+
+/*
+** {======================================================
+** Quicksort
+** (based on `Algorithms in MODULA-3', Robert Sedgewick;
+**  Addison-Wesley, 1993.)
+*/
+
+
+static void set2 (lua_State *L, int i, int j) {
+  lua_rawseti(L, 1, i);
+  lua_rawseti(L, 1, j);
+}
+
+static int sort_comp (lua_State *L, int a, int b) {
+  if (!lua_isnil(L, 2)) {  /* function? */
+    int res;
+    lua_pushvalue(L, 2);
+    lua_pushvalue(L, a-1);  /* -1 to compensate function */
+    lua_pushvalue(L, b-2);  /* -2 to compensate function and `a' */
+    lua_call(L, 2, 1);
+    res = lua_toboolean(L, -1);
+    lua_pop(L, 1);
+    return res;
+  }
+  else  /* a < b? */
+    return lua_lessthan(L, a, b);
+}
+
+static void auxsort (lua_State *L, int l, int u) {
+  while (l < u) {  /* for tail recursion */
+    int i, j;
+    /* sort elements a[l], a[(l+u)/2] and a[u] */
+    lua_rawgeti(L, 1, l);
+    lua_rawgeti(L, 1, u);
+    if (sort_comp(L, -1, -2))  /* a[u] < a[l]? */
+      set2(L, l, u);  /* swap a[l] - a[u] */
+    else
+      lua_pop(L, 2);
+    if (u-l == 1) break;  /* only 2 elements */
+    i = (l+u)/2;
+    lua_rawgeti(L, 1, i);
+    lua_rawgeti(L, 1, l);
+    if (sort_comp(L, -2, -1))  /* a[i]<a[l]? */
+      set2(L, i, l);
+    else {
+      lua_pop(L, 1);  /* remove a[l] */
+      lua_rawgeti(L, 1, u);
+      if (sort_comp(L, -1, -2))  /* a[u]<a[i]? */
+        set2(L, i, u);
+      else
+        lua_pop(L, 2);
+    }
+    if (u-l == 2) break;  /* only 3 elements */
+    lua_rawgeti(L, 1, i);  /* Pivot */
+    lua_pushvalue(L, -1);
+    lua_rawgeti(L, 1, u-1);
+    set2(L, i, u-1);
+    /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
+    i = l; j = u-1;
+    for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */
+      /* repeat ++i until a[i] >= P */
+      while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
+        if (i>u) luaL_error(L, "invalid order function for sorting");
+        lua_pop(L, 1);  /* remove a[i] */
+      }
+      /* repeat --j until a[j] <= P */
+      while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
+        if (j<l) luaL_error(L, "invalid order function for sorting");
+        lua_pop(L, 1);  /* remove a[j] */
+      }
+      if (j<i) {
+        lua_pop(L, 3);  /* pop pivot, a[i], a[j] */
+        break;
+      }
+      set2(L, i, j);
+    }
+    lua_rawgeti(L, 1, u-1);
+    lua_rawgeti(L, 1, i);
+    set2(L, u-1, i);  /* swap pivot (a[u-1]) with a[i] */
+    /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
+    /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
+    if (i-l < u-i) {
+      j=l; i=i-1; l=i+2;
+    }
+    else {
+      j=i+1; i=u; u=j-2;
+    }
+    auxsort(L, j, i);  /* call recursively the smaller one */
+  }  /* repeat the routine for the larger one */
+}
+
+static int sort (lua_State *L) {
+  int n = aux_getn(L, 1);
+  luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */
+  if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
+    luaL_checktype(L, 2, LUA_TFUNCTION);
+  lua_settop(L, 2);  /* make sure there is two arguments */
+  auxsort(L, 1, n);
+  return 0;
+}
+
+/* }====================================================== */
+
+
+static const luaL_Reg tab_funcs[] = {
+  {"concat", tconcat},
+  {"foreach", foreach},
+  {"foreachi", foreachi},
+  {"getn", getn},
+  {"maxn", maxn},
+  {"insert", tinsert},
+  {"remove", tremove},
+  {"setn", setn},
+  {"sort", sort},
+  {NULL, NULL}
+};
+
+
+LUALIB_API int luaopen_table (lua_State *L) {
+  luaL_register(L, LUA_TABLIBNAME, tab_funcs);
+  return 1;
+}
+

=== added file 'lua/ltm.c'
--- lua/ltm.c	1970-01-01 00:00:00 +0000
+++ lua/ltm.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,77 @@
+/*
+** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define ltm_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+
+
+
+const char *const luaT_typenames[] = {
+  "nil", "boolean", "userdata", "number",
+  "string", "table", "function", "userdata", "thread",
+  "proto", "upval"
+};
+
+
+void luaT_init (lua_State *L) {
+  static const char *const luaT_eventname[] = {  /* ORDER TM */
+    "__index", "__newindex",
+    "__gc", "__mode", "__eq",
+    "__add", "__sub", "__mul", "__div", "__mod",
+    "__pow", "__unm", "__len", "__lt", "__le",
+    "__concat", "__call"
+  };
+  int i;
+  for (i=0; i<TM_N; i++) {
+    G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
+    luaS_fix(G(L)->tmname[i]);  /* never collect these names */
+  }
+}
+
+
+/*
+** function to be used with macro "fasttm": optimized for absence of
+** tag methods
+*/
+const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
+  const TValue *tm = luaH_getstr(events, ename);
+  lua_assert(event <= TM_EQ);
+  if (ttisnil(tm)) {  /* no tag method? */
+    events->flags |= cast_byte(1u<<event);  /* cache this fact */
+    return NULL;
+  }
+  else return tm;
+}
+
+
+const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
+  Table *mt;
+  switch (ttype(o)) {
+    case LUA_TTABLE:
+      mt = hvalue(o)->metatable;
+      break;
+    case LUA_TUSERDATA:
+      mt = uvalue(o)->metatable;
+      break;
+    default:
+      mt = G(L)->mt[ttype(o)];
+  }
+  return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+}
+

=== added file 'lua/ltm.h'
--- lua/ltm.h	1970-01-01 00:00:00 +0000
+++ lua/ltm.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,54 @@
+/*
+** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $
+** Tag methods
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltm_h
+#define ltm_h
+
+
+#include "lobject.h"
+
+
+/*
+* WARNING: if you change the order of this enumeration,
+* grep "ORDER TM"
+*/
+typedef enum {
+  TM_INDEX,
+  TM_NEWINDEX,
+  TM_GC,
+  TM_MODE,
+  TM_EQ,  /* last tag method with `fast' access */
+  TM_ADD,
+  TM_SUB,
+  TM_MUL,
+  TM_DIV,
+  TM_MOD,
+  TM_POW,
+  TM_UNM,
+  TM_LEN,
+  TM_LT,
+  TM_LE,
+  TM_CONCAT,
+  TM_CALL,
+  TM_N		/* number of elements in the enum */
+} TMS;
+
+
+
+#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
+  ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
+
+#define fasttm(l,et,e)	gfasttm(G(l), et, e)
+
+LUAI_DATA const char *const luaT_typenames[];
+
+
+LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
+LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
+                                                       TMS event);
+LUAI_FUNC void luaT_init (lua_State *L);
+
+#endif

=== added file 'lua/lua.c'
--- lua/lua.c	1970-01-01 00:00:00 +0000
+++ lua/lua.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,418 @@
+/*
+** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
+** Lua stand-alone interpreter
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define STDERR_PRINTF(format, args...) fprintf(stderr, format, ##args)
+#define STDERR_FLUSH() fflush(stderr)
+#define PRINT(s) fputs(s, stdout)
+#define FLUSH() fflush(stdout)
+#define GETENV(name) getenv(name)
+
+#else /* USE_GRUB_LIB */
+#include "luacmd.h"
+#define STDERR_PRINTF(format, args...) grub_printf(format, ##args)
+#define STDERR_FLUSH()
+#define PRINT(s) grub_printf("%s", s)
+#define FLUSH()
+#define GETENV(name) grub_env_get(name)
+
+#endif /* USE_GRUB_LIB */
+
+#define lua_c
+
+#include "lua.h"
+
+#include "lauxlib.h"
+#include "lualib.h"
+
+
+
+static lua_State *globalL = NULL;
+
+static const char *progname = LUA_PROGNAME;
+
+#ifndef USE_GRUB_LIB
+static void lstop (lua_State *L, lua_Debug *ar) {
+  (void)ar;  /* unused arg. */
+  lua_sethook(L, NULL, 0, 0);
+  luaL_error(L, "interrupted!");
+}
+
+
+static void laction (int i) {
+  signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
+                              terminate process (default action) */
+  lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+}
+#endif /* ! USE_GRUB_LIB */
+
+
+static void print_usage (void) {
+  STDERR_PRINTF(
+  "usage: %s [options] [script [args]].\n"
+  "Available options are:\n"
+  "  -e stat  execute string " LUA_QL("stat") "\n"
+  "  -l name  require library " LUA_QL("name") "\n"
+  "  -i       enter interactive mode after executing " LUA_QL("script") "\n"
+  "  -v       show version information\n"
+  "  --       stop handling options\n"
+  "  -        execute stdin and stop handling options\n"
+  ,
+  progname);
+  STDERR_FLUSH();
+}
+
+
+static void l_message (const char *pname, const char *msg) {
+  if (pname) 
+    STDERR_PRINTF("%s: ", pname);
+  STDERR_PRINTF("%s\n", msg);
+  STDERR_FLUSH();
+}
+
+
+static int report (lua_State *L, int status) {
+  if (status && !lua_isnil(L, -1)) {
+    const char *msg = lua_tostring(L, -1);
+    if (msg == NULL) msg = "(error object is not a string)";
+    l_message(progname, msg);
+    lua_pop(L, 1);
+  }
+  return status;
+}
+
+
+static int traceback (lua_State *L) {
+  if (!lua_isstring(L, 1))  /* 'message' not a string? */
+    return 1;  /* keep it intact */
+  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
+  if (!lua_istable(L, -1)) {
+    lua_pop(L, 1);
+    return 1;
+  }
+  lua_getfield(L, -1, "traceback");
+  if (!lua_isfunction(L, -1)) {
+    lua_pop(L, 2);
+    return 1;
+  }
+  lua_pushvalue(L, 1);  /* pass error message */
+  lua_pushinteger(L, 2);  /* skip this function and traceback */
+  lua_call(L, 2, 1);  /* call debug.traceback */
+  return 1;
+}
+
+
+static int docall (lua_State *L, int narg, int clear) {
+  int status;
+  int base = lua_gettop(L) - narg;  /* function index */
+  lua_pushcfunction(L, traceback);  /* push traceback function */
+  lua_insert(L, base);  /* put it under chunk and args */
+#ifndef USE_GRUB_LIB
+  signal(SIGINT, laction);
+#endif /* ! USE_GRUB_LIB */
+  status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
+#ifndef USE_GRUB_LIB
+  signal(SIGINT, SIG_DFL);
+#endif /* ! USE_GRUB_LIB */
+  lua_remove(L, base);  /* remove traceback function */
+  /* force a complete garbage collection in case of errors */
+  if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
+  return status;
+}
+
+
+static void print_version (void) {
+  l_message(NULL, LUA_RELEASE "  " LUA_COPYRIGHT);
+}
+
+
+static int getargs (lua_State *L, char **argv, int n) {
+  int narg;
+  int i;
+  int argc = 0;
+  while (argv[argc]) argc++;  /* count total number of arguments */
+  narg = argc - (n + 1);  /* number of arguments to the script */
+  luaL_checkstack(L, narg + 3, "too many arguments to script");
+  for (i=n+1; i < argc; i++)
+    lua_pushstring(L, argv[i]);
+  lua_createtable(L, narg, n + 1);
+  for (i=0; i < argc; i++) {
+    lua_pushstring(L, argv[i]);
+    lua_rawseti(L, -2, i - n);
+  }
+  return narg;
+}
+
+
+static int dofile (lua_State *L, const char *name) {
+  int status = luaL_loadfile(L, name) || docall(L, 0, 1);
+  return report(L, status);
+}
+
+
+static int dostring (lua_State *L, const char *s, const char *name) {
+  int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
+  return report(L, status);
+}
+
+
+static int dolibrary (lua_State *L, const char *name) {
+  lua_getglobal(L, "require");
+  lua_pushstring(L, name);
+  return report(L, docall(L, 1, 1));
+}
+
+
+static const char *get_prompt (lua_State *L, int firstline) {
+  const char *p;
+  lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
+  p = lua_tostring(L, -1);
+  if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
+  lua_pop(L, 1);  /* remove global */
+  return p;
+}
+
+
+static int incomplete (lua_State *L, int status) {
+  if (status == LUA_ERRSYNTAX) {
+    size_t lmsg;
+    const char *msg = lua_tolstring(L, -1, &lmsg);
+    const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
+    if (strstr(msg, LUA_QL("<eof>")) == tp) {
+      lua_pop(L, 1);
+      return 1;
+    }
+  }
+  return 0;  /* else... */
+}
+
+
+static int pushline (lua_State *L, int firstline) {
+  char buffer[LUA_MAXINPUT];
+  char *b = buffer;
+  size_t l;
+  const char *prmt = get_prompt(L, firstline);
+  if (lua_readline(L, b, prmt) == 0)
+    return 0;  /* no input */
+  l = strlen(b);
+  if (l > 0 && b[l-1] == '\n')  /* line ends with newline? */
+    b[l-1] = '\0';  /* remove it */
+  if (firstline && b[0] == '=')  /* first line starts with `=' ? */
+    lua_pushfstring(L, "return %s", b+1);  /* change it to `return' */
+  else
+    lua_pushstring(L, b);
+  lua_freeline(L, b);
+  return 1;
+}
+
+
+static int loadline (lua_State *L) {
+  int status;
+  lua_settop(L, 0);
+  if (!pushline(L, 1))
+    return -1;  /* no input */
+  for (;;) {  /* repeat until gets a complete line */
+    status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
+    if (!incomplete(L, status)) break;  /* cannot try to add lines? */
+    if (!pushline(L, 0))  /* no more input? */
+      return -1;
+    lua_pushliteral(L, "\n");  /* add a new line... */
+    lua_insert(L, -2);  /* ...between the two lines */
+    lua_concat(L, 3);  /* join them */
+  }
+  lua_saveline(L, 1);
+  lua_remove(L, 1);  /* remove line */
+  return status;
+}
+
+
+static void dotty (lua_State *L) {
+  int status;
+  const char *oldprogname = progname;
+  progname = NULL;
+  while ((status = loadline(L)) != -1) {
+    if (status == 0) status = docall(L, 0, 0);
+    report(L, status);
+    if (status == 0 && lua_gettop(L) > 0) {  /* any result to print? */
+      lua_getglobal(L, "print");
+      lua_insert(L, 1);
+      if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
+        l_message(progname, lua_pushfstring(L,
+                               "error calling " LUA_QL("print") " (%s)",
+                               lua_tostring(L, -1)));
+    }
+  }
+  lua_settop(L, 0);  /* clear stack */
+  PRINT("\n");
+  FLUSH();
+  progname = oldprogname;
+}
+
+
+static int handle_script (lua_State *L, char **argv, int n) {
+  int status;
+  const char *fname;
+  int narg = getargs(L, argv, n);  /* collect arguments */
+  lua_setglobal(L, "arg");
+  fname = argv[n];
+  if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) 
+    fname = NULL;  /* stdin */
+  status = luaL_loadfile(L, fname);
+  lua_insert(L, -(narg+1));
+  if (status == 0)
+    status = docall(L, narg, 0);
+  else
+    lua_pop(L, narg);      
+  return report(L, status);
+}
+
+
+/* check that argument has no extra characters at the end */
+#define notail(x)	{if ((x)[2] != '\0') return -1;}
+
+
+static int collectargs (char **argv, int *pi, int *pv, int *pe) {
+  int i;
+  for (i = 1; argv[i] != NULL; i++) {
+    if (argv[i][0] != '-')  /* not an option? */
+        return i;
+    switch (argv[i][1]) {  /* option */
+      case '-':
+        notail(argv[i]);
+        return (argv[i+1] != NULL ? i+1 : 0);
+      case '\0':
+        return i;
+      case 'i':
+        notail(argv[i]);
+        *pi = 1;  /* go through */
+      case 'v':
+        notail(argv[i]);
+        *pv = 1;
+        break;
+      case 'e':
+        *pe = 1;  /* go through */
+      case 'l':
+        if (argv[i][2] == '\0') {
+          i++;
+          if (argv[i] == NULL) return -1;
+        }
+        break;
+      default: return -1;  /* invalid option */
+    }
+  }
+  return 0;
+}
+
+
+static int runargs (lua_State *L, char **argv, int n) {
+  int i;
+  for (i = 1; i < n; i++) {
+    if (argv[i] == NULL) continue;
+    lua_assert(argv[i][0] == '-');
+    switch (argv[i][1]) {  /* option */
+      case 'e': {
+        const char *chunk = argv[i] + 2;
+        if (*chunk == '\0') chunk = argv[++i];
+        lua_assert(chunk != NULL);
+        if (dostring(L, chunk, "=(command line)") != 0)
+          return 1;
+        break;
+      }
+      case 'l': {
+        const char *filename = argv[i] + 2;
+        if (*filename == '\0') filename = argv[++i];
+        lua_assert(filename != NULL);
+        if (dolibrary(L, filename))
+          return 1;  /* stop if file fails */
+        break;
+      }
+      default: break;
+    }
+  }
+  return 0;
+}
+
+
+static int handle_luainit (lua_State *L) {
+  const char *init = GETENV(LUA_INIT);
+  if (init == NULL) return 0;  /* status OK */
+  else if (init[0] == '@')
+    return dofile(L, init+1);
+  else
+    return dostring(L, init, "=" LUA_INIT);
+}
+
+
+struct Smain {
+  int argc;
+  char **argv;
+  int status;
+};
+
+
+static int pmain (lua_State *L) {
+  struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
+  char **argv = s->argv;
+  int script;
+  int has_i = 0, has_v = 0, has_e = 0;
+  globalL = L;
+  if (argv[0] && argv[0][0]) progname = argv[0];
+  lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
+  luaL_openlibs(L);  /* open libraries */
+  lua_gc(L, LUA_GCRESTART, 0);
+  s->status = handle_luainit(L);
+  if (s->status != 0) return 0;
+  script = collectargs(argv, &has_i, &has_v, &has_e);
+  if (script < 0) {  /* invalid args? */
+    print_usage();
+    s->status = 1;
+    return 0;
+  }
+  if (has_v) print_version();
+  s->status = runargs(L, argv, (script > 0) ? script : s->argc);
+  if (s->status != 0) return 0;
+  if (script)
+    s->status = handle_script(L, argv, script);
+  if (s->status != 0) return 0;
+  if (has_i)
+    dotty(L);
+  else if (script == 0 && !has_e && !has_v) {
+    if (lua_stdin_is_tty()) {
+      print_version();
+      dotty(L);
+    }
+    else dofile(L, NULL);  /* executes stdin as a file */
+  }
+  return 0;
+}
+
+
+#ifdef GRUB_COMMAND
+int grub_lua_main (int argc, char **argv) {
+#else
+int main (int argc, char **argv) {
+#endif /* ! USE_GRUB_LIB */
+  int status;
+  struct Smain s;
+  lua_State *L = lua_open();  /* create state */
+  if (L == NULL) {
+    l_message(argv[0], "cannot create state: not enough memory");
+    return EXIT_FAILURE;
+  }
+  s.argc = argc;
+  s.argv = argv;
+  status = lua_cpcall(L, &pmain, &s);
+  report(L, status);
+  lua_close(L);
+  return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+

=== added file 'lua/lua.h'
--- lua/lua.h	1970-01-01 00:00:00 +0000
+++ lua/lua.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,388 @@
+/*
+** $Id: lua.h,v 1.218.1.4 2008/01/03 15:41:15 roberto Exp $
+** Lua - An Extensible Extension Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION	"Lua 5.1"
+#define LUA_RELEASE	"Lua 5.1.3"
+#define LUA_VERSION_NUM	501
+#define LUA_COPYRIGHT	"Copyright (C) 1994-2008 Lua.org, PUC-Rio"
+#define LUA_AUTHORS 	"R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
+
+
+/* mark for precompiled code (`<esc>Lua') */
+#define	LUA_SIGNATURE	"\033Lua"
+
+/* option for multiple returns in `lua_pcall' and `lua_call' */
+#define LUA_MULTRET	(-1)
+
+
+/*
+** pseudo-indices
+*/
+#define LUA_REGISTRYINDEX	(-10000)
+#define LUA_ENVIRONINDEX	(-10001)
+#define LUA_GLOBALSINDEX	(-10002)
+#define lua_upvalueindex(i)	(LUA_GLOBALSINDEX-(i))
+
+
+/* thread status; 0 is OK */
+#define LUA_YIELD	1
+#define LUA_ERRRUN	2
+#define LUA_ERRSYNTAX	3
+#define LUA_ERRMEM	4
+#define LUA_ERRERR	5
+
+
+typedef struct lua_State lua_State;
+
+typedef int (*lua_CFunction) (lua_State *L);
+
+
+/*
+** functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
+
+
+/*
+** prototype for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE		(-1)
+
+#define LUA_TNIL		0
+#define LUA_TBOOLEAN		1
+#define LUA_TLIGHTUSERDATA	2
+#define LUA_TNUMBER		3
+#define LUA_TSTRING		4
+#define LUA_TTABLE		5
+#define LUA_TFUNCTION		6
+#define LUA_TUSERDATA		7
+#define LUA_TTHREAD		8
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK	20
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void       (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int   (lua_gettop) (lua_State *L);
+LUA_API void  (lua_settop) (lua_State *L, int idx);
+LUA_API void  (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void  (lua_remove) (lua_State *L, int idx);
+LUA_API void  (lua_insert) (lua_State *L, int idx);
+LUA_API void  (lua_replace) (lua_State *L, int idx);
+LUA_API int   (lua_checkstack) (lua_State *L, int sz);
+
+LUA_API void  (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int             (lua_isnumber) (lua_State *L, int idx);
+LUA_API int             (lua_isstring) (lua_State *L, int idx);
+LUA_API int             (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int             (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int             (lua_type) (lua_State *L, int idx);
+LUA_API const char     *(lua_typename) (lua_State *L, int tp);
+
+LUA_API int            (lua_equal) (lua_State *L, int idx1, int idx2);
+LUA_API int            (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int            (lua_lessthan) (lua_State *L, int idx1, int idx2);
+
+LUA_API lua_Number      (lua_tonumber) (lua_State *L, int idx);
+LUA_API lua_Integer     (lua_tointeger) (lua_State *L, int idx);
+LUA_API int             (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t          (lua_objlen) (lua_State *L, int idx);
+LUA_API lua_CFunction   (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void	       *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State      *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void     *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void  (lua_pushnil) (lua_State *L);
+LUA_API void  (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void  (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API void  (lua_pushlstring) (lua_State *L, const char *s, size_t l);
+LUA_API void  (lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+                                                      va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void  (lua_pushboolean) (lua_State *L, int b);
+LUA_API void  (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int   (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API void  (lua_gettable) (lua_State *L, int idx);
+LUA_API void  (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API void  (lua_rawget) (lua_State *L, int idx);
+LUA_API void  (lua_rawgeti) (lua_State *L, int idx, int n);
+LUA_API void  (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int   (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API void  (lua_getfenv) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void  (lua_settable) (lua_State *L, int idx);
+LUA_API void  (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void  (lua_rawset) (lua_State *L, int idx);
+LUA_API void  (lua_rawseti) (lua_State *L, int idx, int n);
+LUA_API int   (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API int   (lua_setfenv) (lua_State *L, int idx);
+
+
+/*
+** `load' and `call' functions (load and run Lua code)
+*/
+LUA_API void  (lua_call) (lua_State *L, int nargs, int nresults);
+LUA_API int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
+LUA_API int   (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
+LUA_API int   (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+                                        const char *chunkname);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int  (lua_yield) (lua_State *L, int nresults);
+LUA_API int  (lua_resume) (lua_State *L, int narg);
+LUA_API int  (lua_status) (lua_State *L);
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP		0
+#define LUA_GCRESTART		1
+#define LUA_GCCOLLECT		2
+#define LUA_GCCOUNT		3
+#define LUA_GCCOUNTB		4
+#define LUA_GCSTEP		5
+#define LUA_GCSETPAUSE		6
+#define LUA_GCSETSTEPMUL	7
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int   (lua_error) (lua_State *L);
+
+LUA_API int   (lua_next) (lua_State *L, int idx);
+
+LUA_API void  (lua_concat) (lua_State *L, int n);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/* 
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_pop(L,n)		lua_settop(L, -(n)-1)
+
+#define lua_newtable(L)		lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f)	lua_pushcclosure(L, (f), 0)
+
+#define lua_strlen(L,i)		lua_objlen(L, (i))
+
+#define lua_isfunction(L,n)	(lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n)	(lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n)	(lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n)		(lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n)	(lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n)	(lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n)		(lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n)	(lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s)	\
+	lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+
+#define lua_setglobal(L,s)	lua_setfield(L, LUA_GLOBALSINDEX, (s))
+#define lua_getglobal(L,s)	lua_getfield(L, LUA_GLOBALSINDEX, (s))
+
+#define lua_tostring(L,i)	lua_tolstring(L, (i), NULL)
+
+
+
+/*
+** compatibility macros and functions
+*/
+
+#define lua_open()	luaL_newstate()
+
+#define lua_getregistry(L)	lua_pushvalue(L, LUA_REGISTRYINDEX)
+
+#define lua_getgccount(L)	lua_gc(L, LUA_GCCOUNT, 0)
+
+#define lua_Chunkreader		lua_Reader
+#define lua_Chunkwriter		lua_Writer
+
+
+/* hack */
+LUA_API void lua_setlevel	(lua_State *from, lua_State *to);
+
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL	0
+#define LUA_HOOKRET	1
+#define LUA_HOOKLINE	2
+#define LUA_HOOKCOUNT	3
+#define LUA_HOOKTAILRET 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL	(1 << LUA_HOOKCALL)
+#define LUA_MASKRET	(1 << LUA_HOOKRET)
+#define LUA_MASKLINE	(1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT	(1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug;  /* activation record */
+
+
+/* Functions to be called by the debuger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
+LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
+LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
+
+LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook lua_gethook (lua_State *L);
+LUA_API int lua_gethookmask (lua_State *L);
+LUA_API int lua_gethookcount (lua_State *L);
+
+
+struct lua_Debug {
+  int event;
+  const char *name;	/* (n) */
+  const char *namewhat;	/* (n) `global', `local', `field', `method' */
+  const char *what;	/* (S) `Lua', `C', `main', `tail' */
+  const char *source;	/* (S) */
+  int currentline;	/* (l) */
+  int nups;		/* (u) number of upvalues */
+  int linedefined;	/* (S) */
+  int lastlinedefined;	/* (S) */
+  char short_src[LUA_IDSIZE]; /* (S) */
+  /* private part */
+  int i_ci;  /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2008 Lua.org, PUC-Rio.  All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+
+
+#endif

=== added file 'lua/luac.c'
--- lua/luac.c	1970-01-01 00:00:00 +0000
+++ lua/luac.c	2008-08-01 15:19:23 +0000
@@ -0,0 +1,200 @@
+/*
+** $Id: luac.c,v 1.54 2006/06/02 17:37:11 lhf Exp $
+** Lua compiler (saves bytecodes to files; also list bytecodes)
+** See Copyright Notice in lua.h
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define luac_c
+#define LUA_CORE
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+
+#define PROGNAME	"luac"		/* default program name */
+#define	OUTPUT		PROGNAME ".out"	/* default output file */
+
+static int listing=0;			/* list bytecodes? */
+static int dumping=1;			/* dump bytecodes? */
+static int stripping=0;			/* strip debug information? */
+static char Output[]={ OUTPUT };	/* default output file name */
+static const char* output=Output;	/* actual output file name */
+static const char* progname=PROGNAME;	/* actual program name */
+
+static void fatal(const char* message)
+{
+ fprintf(stderr,"%s: %s\n",progname,message);
+ exit(EXIT_FAILURE);
+}
+
+static void cannot(const char* what)
+{
+ fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
+ exit(EXIT_FAILURE);
+}
+
+static void usage(const char* message)
+{
+ if (*message=='-')
+  fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
+ else
+  fprintf(stderr,"%s: %s\n",progname,message);
+ fprintf(stderr,
+ "usage: %s [options] [filenames].\n"
+ "Available options are:\n"
+ "  -        process stdin\n"
+ "  -l       list\n"
+ "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n"
+ "  -p       parse only\n"
+ "  -s       strip debug information\n"
+ "  -v       show version information\n"
+ "  --       stop handling options\n",
+ progname,Output);
+ exit(EXIT_FAILURE);
+}
+
+#define	IS(s)	(strcmp(argv[i],s)==0)
+
+static int doargs(int argc, char* argv[])
+{
+ int i;
+ int version=0;
+ if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
+ for (i=1; i<argc; i++)
+ {
+  if (*argv[i]!='-')			/* end of options; keep it */
+   break;
+  else if (IS("--"))			/* end of options; skip it */
+  {
+   ++i;
+   if (version) ++version;
+   break;
+  }
+  else if (IS("-"))			/* end of options; use stdin */
+   break;
+  else if (IS("-l"))			/* list */
+   ++listing;
+  else if (IS("-o"))			/* output file */
+  {
+   output=argv[++i];
+   if (output==NULL || *output==0) usage(LUA_QL("-o") " needs argument");
+   if (IS("-")) output=NULL;
+  }
+  else if (IS("-p"))			/* parse only */
+   dumping=0;
+  else if (IS("-s"))			/* strip debug information */
+   stripping=1;
+  else if (IS("-v"))			/* show version */
+   ++version;
+  else					/* unknown option */
+   usage(argv[i]);
+ }
+ if (i==argc && (listing || !dumping))
+ {
+  dumping=0;
+  argv[--i]=Output;
+ }
+ if (version)
+ {
+  printf("%s  %s\n",LUA_RELEASE,LUA_COPYRIGHT);
+  if (version==argc-1) exit(EXIT_SUCCESS);
+ }
+ return i;
+}
+
+#define toproto(L,i) (clvalue(L->top+(i))->l.p)
+
+static const Proto* combine(lua_State* L, int n)
+{
+ if (n==1)
+  return toproto(L,-1);
+ else
+ {
+  int i,pc;
+  Proto* f=luaF_newproto(L);
+  setptvalue2s(L,L->top,f); incr_top(L);
+  f->source=luaS_newliteral(L,"=(" PROGNAME ")");
+  f->maxstacksize=1;
+  pc=2*n+1;
+  f->code=luaM_newvector(L,pc,Instruction);
+  f->sizecode=pc;
+  f->p=luaM_newvector(L,n,Proto*);
+  f->sizep=n;
+  pc=0;
+  for (i=0; i<n; i++)
+  {
+   f->p[i]=toproto(L,i-n-1);
+   f->code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
+   f->code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
+  }
+  f->code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
+  return f;
+ }
+}
+
+static int writer(lua_State* L, const void* p, size_t size, void* u)
+{
+ UNUSED(L);
+ return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
+}
+
+struct Smain {
+ int argc;
+ char** argv;
+};
+
+static int pmain(lua_State* L)
+{
+ struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
+ int argc=s->argc;
+ char** argv=s->argv;
+ const Proto* f;
+ int i;
+ if (!lua_checkstack(L,argc)) fatal("too many input files");
+ for (i=0; i<argc; i++)
+ {
+  const char* filename=IS("-") ? NULL : argv[i];
+  if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));
+ }
+ f=combine(L,argc);
+ if (listing) luaU_print(f,listing>1);
+ if (dumping)
+ {
+  FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
+  if (D==NULL) cannot("open");
+  lua_lock(L);
+  luaU_dump(L,f,writer,D,stripping);
+  lua_unlock(L);
+  if (ferror(D)) cannot("write");
+  if (fclose(D)) cannot("close");
+ }
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ lua_State* L;
+ struct Smain s;
+ int i=doargs(argc,argv);
+ argc-=i; argv+=i;
+ if (argc<=0) usage("no input files given");
+ L=lua_open();
+ if (L==NULL) fatal("not enough memory for state");
+ s.argc=argc;
+ s.argv=argv;
+ if (lua_cpcall(L,pmain,&s)!=0) fatal(lua_tostring(L,-1));
+ lua_close(L);
+ return EXIT_SUCCESS;
+}

=== added file 'lua/luacmd.c'
--- lua/luacmd.c	1970-01-01 00:00:00 +0000
+++ lua/luacmd.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,69 @@
+/* luacmd.c - Lua interpreter command */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include "luacmd.h"
+#include "lua.h"
+#include "lauxlib.h"
+
+static grub_err_t
+grub_cmd_lua (struct grub_arg_list *state __attribute__ ((unused)),
+              int argc,
+              char **argv)
+{
+  /* Make a copy of the GRUB command's argv so we can put the command
+     name at index 0, like Lua's main function expects, as well as
+     terminating the argv array with a NULL pointer.  */
+
+  char **main_argv = grub_malloc (sizeof (char *) * (argc + 2));
+  if (! main_argv)
+    return grub_errno;
+
+  main_argv[0] = "lua";
+  grub_memcpy (&main_argv[1], argv, sizeof (char *) * (argc + 1));
+  main_argv[argc + 1] = 0;
+
+  int ret;
+  ret = grub_lua_main (argc + 1, main_argv);
+  grub_free (main_argv);
+
+  return ret;
+}
+
+GRUB_MOD_INIT(luacmd)
+{
+  (void)mod;                    /* To stop warning. */
+  /* We use the NO_ARG_PARSE flag so command line options are passed
+     to the Lua interpreter for handling.  */
+  grub_register_command ("lua", grub_cmd_lua, 
+                         (GRUB_COMMAND_FLAG_BOTH 
+                          | GRUB_COMMAND_FLAG_NO_ARG_PARSE),
+                         "lua", "Run the Lua interpreter", 0);
+}
+
+GRUB_MOD_FINI(luacmd)
+{
+  grub_unregister_command ("lua");
+}
+

=== added file 'lua/luacmd.h'
--- lua/luacmd.h	1970-01-01 00:00:00 +0000
+++ lua/luacmd.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,25 @@
+/* luacmd.h - Lua command include file. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LUA_LUACMD_HEADER
+#define GRUB_LUA_LUACMD_HEADER 1
+
+int grub_lua_main (int argc, char **argv);
+
+#endif /* ! GRUB_LUA_LUACMD_HEADER */

=== added file 'lua/luaconf.h'
--- lua/luaconf.h	1970-01-01 00:00:00 +0000
+++ lua/luaconf.h	2008-08-01 15:27:27 +0000
@@ -0,0 +1,849 @@
+/*
+** $Id: luaconf.h,v 1.82.1.6 2008/01/18 17:07:48 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lconfig_h
+#define lconfig_h
+
+#include <stddef.h>
+#ifndef USE_GRUB_LIB
+#include <limits.h>
+#else /* USE_GRUB_LIB */
+# include "grublib.h"
+# include <grub/types.h>
+# include <grub/misc.h>
+# define assert(boolean) real_assert (boolean, __FILE__, __LINE__)
+static inline void
+real_assert (int boolean, const char *file, const int line)
+{
+  if (! boolean)
+    grub_printf ("Assertion failed at %s:%d\n", file, line);
+}
+#endif /* USE_GRUB_LIB */
+
+
+/*
+** ==================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+@@ LUA_ANSI controls the use of non-ansi features.
+** CHANGE it (define it) if you want Lua to avoid the use of any
+** non-ansi feature or library.
+*/
+#if defined(__STRICT_ANSI__)
+#define LUA_ANSI
+#endif
+
+
+#if !defined(LUA_ANSI) && defined(_WIN32)
+#define LUA_WIN
+#endif
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
+#define LUA_USE_READLINE	/* needs some extra libraries */
+#endif
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_DL_DYLD		/* does not need extra library */
+#endif
+
+
+
+/*
+@@ LUA_USE_POSIX includes all functionallity listed as X/Open System
+@* Interfaces Extension (XSI).
+** CHANGE it (define it) if your system is XSI compatible.
+*/
+#if defined(LUA_USE_POSIX)
+#define LUA_USE_MKSTEMP
+#define LUA_USE_ISATTY
+#define LUA_USE_POPEN
+#define LUA_USE_ULONGJMP
+#endif
+
+
+/*
+@@ LUA_PATH and LUA_CPATH are the names of the environment variables that
+@* Lua check to set its paths.
+@@ LUA_INIT is the name of the environment variable that Lua
+@* checks for initialization code.
+** CHANGE them if you want different names.
+*/
+#define LUA_PATH        "LUA_PATH"
+#define LUA_CPATH       "LUA_CPATH"
+#define LUA_INIT	"LUA_INIT"
+
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+@* Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+@* C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#if defined(_WIN32)
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR	"!\\lua\\"
+#define LUA_CDIR	"!\\"
+#define LUA_PATH_DEFAULT  \
+		".\\?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?\\init.lua;" \
+		             LUA_CDIR"?.lua;"  LUA_CDIR"?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+	".\\?.dll;"  LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
+
+#else
+#define LUA_ROOT	"/usr/local/"
+#define LUA_LDIR	LUA_ROOT "share/lua/5.1/"
+#define LUA_CDIR	LUA_ROOT "lib/lua/5.1/"
+#define LUA_PATH_DEFAULT  \
+		"./?.lua;"  LUA_LDIR"?.lua;"  LUA_LDIR"?/init.lua;" \
+		            LUA_CDIR"?.lua;"  LUA_CDIR"?/init.lua"
+#define LUA_CPATH_DEFAULT \
+	"./?.so;"  LUA_CDIR"?.so;" LUA_CDIR"loadall.so"
+#endif
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP	"\\"
+#else
+#define LUA_DIRSEP	"/"
+#endif
+
+
+/*
+@@ LUA_PATHSEP is the character that separates templates in a path.
+@@ LUA_PATH_MARK is the string that marks the substitution points in a
+@* template.
+@@ LUA_EXECDIR in a Windows path is replaced by the executable's
+@* directory.
+@@ LUA_IGMARK is a mark to ignore all before it when bulding the
+@* luaopen_ function name.
+** CHANGE them if for some reason your system cannot use those
+** characters. (E.g., if one of those characters is a common character
+** in file/directory names.) Probably you do not need to change them.
+*/
+#define LUA_PATHSEP	";"
+#define LUA_PATH_MARK	"?"
+#define LUA_EXECDIR	"!"
+#define LUA_IGMARK	"-"
+
+
+/*
+@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
+** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
+** machines, ptrdiff_t gives a good choice between int or long.)
+*/
+
+/* Changed to long for use with integral Lua numbers. */
+#define LUA_INTEGER	long
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all standard library functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL)
+
+#if defined(LUA_CORE) || defined(LUA_LIB)
+#define LUA_API __declspec(dllexport)
+#else
+#define LUA_API __declspec(dllimport)
+#endif
+
+#else
+
+#define LUA_API		extern
+
+#endif
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API	LUA_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+@* exported to outside modules.
+@@ LUAI_DATA is a mark for all extern (const) variables that are not to
+@* be exported to outside modules.
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library.
+*/
+#if defined(luaall_c)
+#define LUAI_FUNC	static
+#define LUAI_DATA	/* empty */
+
+#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+      defined(__ELF__)
+#define LUAI_FUNC	__attribute__((visibility("hidden"))) extern
+#define LUAI_DATA	LUAI_FUNC
+
+#else
+#define LUAI_FUNC	extern
+#define LUAI_DATA	extern
+#endif
+
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** CHANGE it if you want a different appearance.
+*/
+#define LUA_QL(x)	"'" x "'"
+#define LUA_QS		LUA_QL("%s")
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@* of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE	60
+
+
+/*
+** {==================================================================
+** Stand-alone configuration
+** ===================================================================
+*/
+
+#if defined(lua_c) || defined(luaall_c)
+
+/*
+@@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that
+@* is, whether we're running lua interactively).
+** CHANGE it if you have a better definition for non-POSIX/non-Windows
+** systems.
+*/
+#if defined(LUA_USE_ISATTY)
+#include <unistd.h>
+#define lua_stdin_is_tty()	isatty(0)
+#elif defined(LUA_WIN)
+#include <io.h>
+#include <stdio.h>
+#define lua_stdin_is_tty()	_isatty(_fileno(stdin))
+#else
+#define lua_stdin_is_tty()	1  /* assume stdin is a tty */
+#endif
+
+
+/*
+@@ LUA_PROMPT is the default prompt used by stand-alone Lua.
+@@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua.
+** CHANGE them if you want different prompts. (You can also change the
+** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.)
+*/
+#define LUA_PROMPT		"> "
+#define LUA_PROMPT2		">> "
+
+
+/*
+@@ LUA_PROGNAME is the default name for the stand-alone Lua program.
+** CHANGE it if your stand-alone interpreter has a different name and
+** your system is not able to detect that name automatically.
+*/
+#define LUA_PROGNAME		"lua"
+
+
+/*
+@@ LUA_MAXINPUT is the maximum length for an input line in the
+@* stand-alone interpreter.
+** CHANGE it if you need longer lines.
+*/
+#define LUA_MAXINPUT	512
+
+
+/*
+@@ lua_readline defines how to show a prompt and then read a line from
+@* the standard input.
+@@ lua_saveline defines how to "save" a read line in a "history".
+@@ lua_freeline defines how to free a line read by lua_readline.
+** CHANGE them if you want to improve this functionality (e.g., by using
+** GNU readline and history facilities).
+*/
+#if defined(LUA_USE_READLINE)
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#define lua_readline(L,b,p)	((void)L, ((b)=readline(p)) != NULL)
+#define lua_saveline(L,idx) \
+	if (lua_strlen(L,idx) > 0)  /* non-empty line? */ \
+	  add_history(lua_tostring(L, idx));  /* add it to history */
+#define lua_freeline(L,b)	((void)L, free(b))
+
+#elif defined(USE_GRUB_LIB)
+#include <grub/normal.h>   /* For grub_cmdline_get(), for user input.  */
+#define lua_readline(L,buf,prompt)	\
+	((void)L, buf[0]=0, grub_cmdline_get(prompt, buf, LUA_MAXINPUT, 0, 1))
+#define lua_saveline(L,idx)	{ (void)L; (void)idx; }
+#define lua_freeline(L,b)	{ (void)L; (void)b; }
+
+#else
+#define lua_readline(L,b,p)	\
+	((void)L, fputs(p, stdout), fflush(stdout),  /* show prompt */ \
+	fgets(b, LUA_MAXINPUT, stdin) != NULL)  /* get line */
+#define lua_saveline(L,idx)	{ (void)L; (void)idx; }
+#define lua_freeline(L,b)	{ (void)L; (void)b; }
+#endif
+
+#endif /* lua_c || luaall_c */
+
+/* }================================================================== */
+
+
+/*
+@@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles
+@* as a percentage.
+** CHANGE it if you want the GC to run faster or slower (higher values
+** mean larger pauses which mean slower collection.) You can also change
+** this value dynamically.
+*/
+#define LUAI_GCPAUSE	200  /* 200% (wait memory to double before next GC) */
+
+
+/*
+@@ LUAI_GCMUL defines the default speed of garbage collection relative to
+@* memory allocation as a percentage.
+** CHANGE it if you want to change the granularity of the garbage
+** collection. (Higher values mean coarser collections. 0 represents
+** infinity, where each step performs a full collection.) You can also
+** change this value dynamically.
+*/
+#define LUAI_GCMUL	200 /* GC runs 'twice the speed' of memory allocation */
+
+
+
+/*
+@@ LUA_COMPAT_GETN controls compatibility with old getn behavior.
+** CHANGE it (define it) if you want exact compatibility with the
+** behavior of setn/getn in Lua 5.0.
+*/
+#undef LUA_COMPAT_GETN
+
+/*
+@@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib.
+** CHANGE it to undefined as soon as you do not need a global 'loadlib'
+** function (the function is still available as 'package.loadlib').
+*/
+#undef LUA_COMPAT_LOADLIB
+
+/*
+@@ LUA_COMPAT_VARARG controls compatibility with old vararg feature.
+** CHANGE it to undefined as soon as your programs use only '...' to
+** access vararg parameters (instead of the old 'arg' table).
+*/
+#define LUA_COMPAT_VARARG
+
+/*
+@@ LUA_COMPAT_MOD controls compatibility with old math.mod function.
+** CHANGE it to undefined as soon as your programs use 'math.fmod' or
+** the new '%' operator instead of 'math.mod'.
+*/
+#define LUA_COMPAT_MOD
+
+/*
+@@ LUA_COMPAT_LSTR controls compatibility with old long string nesting
+@* facility.
+** CHANGE it to 2 if you want the old behaviour, or undefine it to turn
+** off the advisory error when nesting [[...]].
+*/
+#define LUA_COMPAT_LSTR		1
+
+/*
+@@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name.
+** CHANGE it to undefined as soon as you rename 'string.gfind' to
+** 'string.gmatch'.
+*/
+#define LUA_COMPAT_GFIND
+
+/*
+@@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib'
+@* behavior.
+** CHANGE it to undefined as soon as you replace to 'luaL_register'
+** your uses of 'luaL_openlib'
+*/
+#define LUA_COMPAT_OPENLIB
+
+
+
+/*
+@@ luai_apicheck is the assert macro used by the Lua-C API.
+** CHANGE luai_apicheck if you want Lua to perform some checks in the
+** parameters it gets from API calls. This may slow down the interpreter
+** a bit, but may be quite useful when debugging C code that interfaces
+** with Lua. A useful redefinition is to use assert.h.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(L,o)	{ (void)L; assert(o); }
+#else
+#define luai_apicheck(L,o)	{ (void)L; }
+#endif
+
+
+/*
+@@ LUAI_BITSINT defines the number of bits in an int.
+** CHANGE here if Lua cannot automatically detect the number of bits of
+** your machine. Probably you do not need to change this.
+*/
+/* avoid overflows in comparison */
+#if INT_MAX-20 < 32760
+#define LUAI_BITSINT	16
+#elif INT_MAX > 2147483640L
+/* int has at least 32 bits */
+#define LUAI_BITSINT	32
+#else
+#error "you must define LUA_BITSINT with number of bits in an integer"
+#endif
+
+
+/*
+@@ LUAI_UINT32 is an unsigned integer with at least 32 bits.
+@@ LUAI_INT32 is an signed integer with at least 32 bits.
+@@ LUAI_UMEM is an unsigned integer big enough to count the total
+@* memory used by Lua.
+@@ LUAI_MEM is a signed integer big enough to count the total memory
+@* used by Lua.
+** CHANGE here if for some weird reason the default definitions are not
+** good enough for your machine. (The definitions in the 'else'
+** part always works, but may waste space on machines with 64-bit
+** longs.) Probably you do not need to change this.
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_UINT32	unsigned int
+#define LUAI_INT32	int
+#define LUAI_MAXINT32	INT_MAX
+#define LUAI_UMEM	size_t
+#define LUAI_MEM	ptrdiff_t
+#else
+/* 16-bit ints */
+#define LUAI_UINT32	unsigned long
+#define LUAI_INT32	long
+#define LUAI_MAXINT32	LONG_MAX
+#define LUAI_UMEM	unsigned long
+#define LUAI_MEM	long
+#endif
+
+
+/*
+@@ LUAI_MAXCALLS limits the number of nested calls.
+** CHANGE it if you need really deep recursive calls. This limit is
+** arbitrary; its only purpose is to stop infinite recursion before
+** exhausting memory.
+*/
+#define LUAI_MAXCALLS	20000
+
+
+/*
+@@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function
+@* can use.
+** CHANGE it if you need lots of (Lua) stack space for your C
+** functions. This limit is arbitrary; its only purpose is to stop C
+** functions to consume unlimited stack space.
+*/
+#define LUAI_MCS_AUX	((int)(INT_MAX / (4*sizeof(LUA_NUMBER))))
+#define LUAI_MAXCSTACK	(LUAI_MCS_AUX > SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX)
+
+
+
+/*
+** {==================================================================
+** CHANGE (to smaller values) the following definitions if your system
+** has a small C stack. (Or you may want to change them to larger
+** values if your system has a large C stack and these limits are
+** too rigid for you.) Some of these constants control the size of
+** stack-allocated arrays used by the compiler or the interpreter, while
+** others limit the maximum number of recursive calls that the compiler
+** or the interpreter can perform. Values too large may cause a C stack
+** overflow for some forms of deep constructs.
+** ===================================================================
+*/
+
+
+/*
+@@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and
+@* syntactical nested non-terminals in a program.
+*/
+#define LUAI_MAXCCALLS		200
+
+
+/*
+@@ LUAI_MAXVARS is the maximum number of local variables per function
+@* (must be smaller than 250).
+*/
+#define LUAI_MAXVARS		200
+
+
+/*
+@@ LUAI_MAXUPVALUES is the maximum number of upvalues per function
+@* (must be smaller than 250).
+*/
+#define LUAI_MAXUPVALUES	60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+*/
+#ifdef USE_GRUB_LIB
+#define LUAL_BUFFERSIZE		32768
+#else
+#define LUAL_BUFFERSIZE		BUFSIZ
+#endif
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+@@ LUA_NUMBER is the type of numbers in Lua.
+** CHANGE the following definitions only if you want to build Lua
+** with a number type different from double. You may also need to
+** change lua_number2int & lua_number2integer.
+** ===================================================================
+*/
+
+/* Define LUA_NUMBER_INTEGRAL to produce a system that uses no
+   floating point operations by changing the type of Lua numbers from
+   double to long.  It implements division and modulus so that 
+
+   x == (x / y) * y + x % y.  
+   
+   The exponentiation function returns zero for negative exponents.
+   Defining LUA_NUMBER_INTEGRAL also removes the difftime function,
+   and the math module should not be used.  The string.format function
+   no longer handles the floating point directives %e, %E, %f, %g, and
+   %G. */
+
+#define LUA_NUMBER_INTEGRAL
+#if defined LUA_NUMBER_INTEGRAL
+#define LUA_NUMBER	long
+#else
+#define LUA_NUMBER_DOUBLE
+#define LUA_NUMBER	double
+#endif
+
+/*
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@* over a number.
+*/
+#define LUAI_UACNUMBER	LUA_NUMBER
+
+
+/*
+@@ LUA_NUMBER_SCAN is the format for reading numbers.
+@@ LUA_NUMBER_FMT is the format for writing numbers.
+@@ lua_number2str converts a number to a string.
+@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
+@@ lua_str2number converts a string to a number.
+*/
+#if defined LUA_NUMBER_INTEGRAL
+#define LUA_NUMBER_SCAN		"%ld"
+#define LUA_NUMBER_FMT		"%ld"
+#else
+#define LUA_NUMBER_SCAN		"%lf"
+#define LUA_NUMBER_FMT		"%.14g"
+#endif
+#define lua_number2str(s,n)	sprintf((s), LUA_NUMBER_FMT, (n))
+#define LUAI_MAXNUMBER2STR	32 /* 16 digits, sign, point, and \0 */
+#if defined LUA_NUMBER_INTEGRAL
+#define lua_str2number(s,p)	strtol((s), (p), 10)
+#else
+#define lua_str2number(s,p)	strtod((s), (p))
+#endif
+
+
+/*
+@@ The luai_num* macros define the primitive operations over numbers.
+*/
+#if defined(LUA_CORE)
+#include <math.h>
+#define luai_numadd(a,b)	((a)+(b))
+#define luai_numsub(a,b)	((a)-(b))
+#define luai_nummul(a,b)	((a)*(b))
+#if defined LUA_NUMBER_INTEGRAL
+#define luai_numdiv(a,b)	\
+  (-1/2?			\
+   (a)/(b):			\
+   (((a)<0)==((b)<0)||(a)%(b)==0?	\
+    (a)/(b):			\
+    (a)/(b)-1))
+#define luai_nummod(a,b)	\
+  (-1/2?			\
+   (a)%(b):			\
+   (((a)<0)==((b)<0)||(a)%(b)==0?	\
+    (a)%(b):			\
+    (a)%(b)+(b)))
+#define luai_lnumdiv(a,b)	\
+  ((b)==0?			\
+   (luaG_runerror(L,"divide by zero"),0): \
+   luai_numdiv(a,b))
+#define luai_lnummod(a,b)	\
+  ((b)==0?			\
+   (luaG_runerror(L,"modulo by zero"),0): \
+   luai_nummod(a,b))
+LUA_NUMBER luai_ipow(LUA_NUMBER, LUA_NUMBER);
+#define luai_numpow(a,b)	(luai_ipow(a,b))
+#else
+#define luai_numdiv(a,b)	((a)/(b))
+#define luai_nummod(a,b)	((a) - floor((a)/(b))*(b))
+#define luai_lnumdiv(a,b)	(luai_numdiv(a,b))
+#define luai_lnummod(a,b)	(luai_nummod(a,b))
+#define luai_numpow(a,b)	(pow(a,b))
+#endif
+#define luai_numunm(a)		(-(a))
+#define luai_numeq(a,b)		((a)==(b))
+#define luai_numlt(a,b)		((a)<(b))
+#define luai_numle(a,b)		((a)<=(b))
+#define luai_numisnan(a)	(!luai_numeq((a), (a)))
+#endif
+
+
+/*
+@@ lua_number2int is a macro to convert lua_Number to int.
+@@ lua_number2integer is a macro to convert lua_Number to lua_Integer.
+** CHANGE them if you know a faster way to convert a lua_Number to
+** int (with any rounding method and without throwing errors) in your
+** system. In Pentium machines, a naive typecast from double to int
+** in C is extremely slow, so any alternative is worth trying.
+*/
+
+/* On a Pentium, resort to a trick */
+#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \
+    (defined(__i386) || defined (_M_IX86) || defined(__i386__))
+
+/* On a Microsoft compiler, use assembler */
+#if defined(_MSC_VER)
+
+#define lua_number2int(i,d)   __asm fld d   __asm fistp i
+#define lua_number2integer(i,n)		lua_number2int(i, n)
+
+/* the next trick should work on any Pentium, but sometimes clashes
+   with a DirectX idiosyncrasy */
+#else
+
+union luai_Cast { double l_d; long l_l; };
+#define lua_number2int(i,d) \
+  { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; }
+#define lua_number2integer(i,n)		lua_number2int(i, n)
+
+#endif
+
+
+/* this option always works, but may be slow */
+#else
+#define lua_number2int(i,d)	((i)=(int)(d))
+#define lua_number2integer(i,d)	((i)=(lua_Integer)(d))
+
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment.
+** CHANGE it if your system requires alignments larger than double. (For
+** instance, if your system supports long doubles and they must be
+** aligned in 16-byte boundaries, then you should add long double in the
+** union.) Probably you do not need to change this.
+*/
+#define LUAI_USER_ALIGNMENT_T	union { double u; void *s; long l; }
+
+
+/*
+@@ LUAI_THROW/LUAI_TRY define how Lua does exception handling.
+** CHANGE them if you prefer to use longjmp/setjmp even with C++
+** or if want/don't to use _longjmp/_setjmp instead of regular
+** longjmp/setjmp. By default, Lua handles errors with exceptions when
+** compiling as C++ code, with _longjmp/_setjmp when asked to use them,
+** and with longjmp/setjmp otherwise.
+*/
+#if defined(USE_GRUB_LIB)
+#include <grub/setjmp.h>
+/* handling with long jumps, using the GRUB functions */
+#define LUAI_THROW(L,c)	grub_longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a)	if (grub_setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf	grub_jmp_buf
+
+#elif defined(__cplusplus)
+/* C++ exceptions */
+#define LUAI_THROW(L,c)	throw(c)
+#define LUAI_TRY(L,c,a)	try { a } catch(...) \
+	{ if ((c)->status == 0) (c)->status = -1; }
+#define luai_jmpbuf	int  /* dummy variable */
+
+#elif defined(LUA_USE_ULONGJMP)
+/* in Unix, try _longjmp/_setjmp (more efficient) */
+#define LUAI_THROW(L,c)	_longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a)	if (_setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf	jmp_buf
+
+#else
+/* default handling with long jumps */
+#define LUAI_THROW(L,c)	longjmp((c)->b, 1)
+#define LUAI_TRY(L,c,a)	if (setjmp((c)->b) == 0) { a }
+#define luai_jmpbuf	jmp_buf
+
+#endif
+
+
+/*
+@@ LUA_MAXCAPTURES is the maximum number of captures that a pattern
+@* can do during pattern-matching.
+** CHANGE it if you need more captures. This limit is arbitrary.
+*/
+#define LUA_MAXCAPTURES		32
+
+
+/*
+@@ lua_tmpnam is the function that the OS library uses to create a
+@* temporary name.
+@@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam.
+** CHANGE them if you have an alternative to tmpnam (which is considered
+** insecure) or if you want the original tmpnam anyway.  By default, Lua
+** uses tmpnam except when POSIX is available, where it uses mkstemp.
+*/
+#if defined(loslib_c) || defined(luaall_c)
+
+#if defined(LUA_USE_MKSTEMP)
+#include <unistd.h>
+#define LUA_TMPNAMBUFSIZE	32
+#define lua_tmpnam(b,e)	{ \
+	strcpy(b, "/tmp/lua_XXXXXX"); \
+	e = mkstemp(b); \
+	if (e != -1) close(e); \
+	e = (e == -1); }
+
+#else
+#define LUA_TMPNAMBUFSIZE	L_tmpnam
+#define lua_tmpnam(b,e)		{ e = (tmpnam(b) == NULL); }
+#endif
+
+#endif
+
+
+/*
+@@ lua_popen spawns a new process connected to the current one through
+@* the file streams.
+** CHANGE it if you have a way to implement it in your system.
+*/
+#if defined(LUA_USE_POPEN)
+
+#define lua_popen(L,c,m)	((void)L, fflush(NULL), popen(c,m))
+#define lua_pclose(L,file)	((void)L, (pclose(file) != -1))
+
+#elif defined(LUA_WIN)
+
+#define lua_popen(L,c,m)	((void)L, _popen(c,m))
+#define lua_pclose(L,file)	((void)L, (_pclose(file) != -1))
+
+#else
+
+#define lua_popen(L,c,m)	((void)((void)c, m),  \
+		luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
+#define lua_pclose(L,file)		((void)((void)L, file), 0)
+
+#endif
+
+/*
+@@ LUA_DL_* define which dynamic-library system Lua should use.
+** CHANGE here if Lua has problems choosing the appropriate
+** dynamic-library system for your platform (either Windows' DLL, Mac's
+** dyld, or Unix's dlopen). If your system is some kind of Unix, there
+** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for
+** it.  To use dlopen you also need to adapt the src/Makefile (probably
+** adding -ldl to the linker options), so Lua does not select it
+** automatically.  (When you change the makefile to add -ldl, you must
+** also add -DLUA_USE_DLOPEN.)
+** If you do not want any kind of dynamic library, undefine all these
+** options.
+** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD.
+*/
+#if defined(LUA_USE_DLOPEN)
+#define LUA_DL_DLOPEN
+#endif
+
+#if defined(LUA_WIN)
+#define LUA_DL_DLL
+#endif
+
+
+/*
+@@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State
+@* (the data goes just *before* the lua_State pointer).
+** CHANGE (define) this if you really need that. This value must be
+** a multiple of the maximum alignment required for your machine.
+*/
+#define LUAI_EXTRASPACE		0
+
+
+/*
+@@ luai_userstate* allow user-specific actions on threads.
+** CHANGE them if you defined LUAI_EXTRASPACE and need to do something
+** extra when a thread is created/deleted/resumed/yielded.
+*/
+#define luai_userstateopen(L)		((void)L)
+#define luai_userstateclose(L)		((void)L)
+#define luai_userstatethread(L,L1)	((void)L)
+#define luai_userstatefree(L)		((void)L)
+#define luai_userstateresume(L,n)	((void)L)
+#define luai_userstateyield(L,n)	((void)L)
+
+
+/*
+@@ LUA_INTFRMLEN is the length modifier for integer conversions
+@* in 'string.format'.
+@@ LUA_INTFRM_T is the integer type correspoding to the previous length
+@* modifier.
+** CHANGE them if your system supports long long or does not support long.
+*/
+
+#if defined(LUA_USELONGLONG)
+
+#define LUA_INTFRMLEN		"ll"
+#define LUA_INTFRM_T		long long
+
+#else
+
+#define LUA_INTFRMLEN		"l"
+#define LUA_INTFRM_T		long
+
+#endif
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+#endif
+

=== added file 'lua/lualib.h'
--- lua/lualib.h	1970-01-01 00:00:00 +0000
+++ lua/lualib.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,53 @@
+/*
+** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+/* Key to file-handle type */
+#define LUA_FILEHANDLE		"FILE*"
+
+
+#define LUA_COLIBNAME	"coroutine"
+LUALIB_API int (luaopen_base) (lua_State *L);
+
+#define LUA_TABLIBNAME	"table"
+LUALIB_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME	"io"
+LUALIB_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME	"os"
+LUALIB_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME	"string"
+LUALIB_API int (luaopen_string) (lua_State *L);
+
+#define LUA_MATHLIBNAME	"math"
+LUALIB_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME	"debug"
+LUALIB_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME	"package"
+LUALIB_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L); 
+
+
+
+#ifndef lua_assert
+#define lua_assert(x)	((void)0)
+#endif
+
+
+#endif

=== added file 'lua/lundump.c'
--- lua/lundump.c	1970-01-01 00:00:00 +0000
+++ lua/lundump.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,227 @@
+/*
+** $Id: lundump.c,v 2.7.1.2 2008/01/18 16:39:11 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lundump_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstring.h"
+#include "lundump.h"
+#include "lzio.h"
+
+typedef struct {
+ lua_State* L;
+ ZIO* Z;
+ Mbuffer* b;
+ const char* name;
+} LoadState;
+
+#ifdef LUAC_TRUST_BINARIES
+#define IF(c,s)
+#define error(S,s)
+#else
+#define IF(c,s)		if (c) error(S,s)
+
+static void error(LoadState* S, const char* why)
+{
+ luaO_pushfstring(S->L,"%s: %s in precompiled chunk",S->name,why);
+ luaD_throw(S->L,LUA_ERRSYNTAX);
+}
+#endif
+
+#define LoadMem(S,b,n,size)	LoadBlock(S,b,(n)*(size))
+#define	LoadByte(S)		(lu_byte)LoadChar(S)
+#define LoadVar(S,x)		LoadMem(S,&x,1,sizeof(x))
+#define LoadVector(S,b,n,size)	LoadMem(S,b,n,size)
+
+static void LoadBlock(LoadState* S, void* b, size_t size)
+{
+ size_t r=luaZ_read(S->Z,b,size);
+ UNUSED(r);
+ IF (r!=0, "unexpected end");
+}
+
+static int LoadChar(LoadState* S)
+{
+ char x;
+ LoadVar(S,x);
+ return x;
+}
+
+static int LoadInt(LoadState* S)
+{
+ int x;
+ LoadVar(S,x);
+ IF (x<0, "bad integer");
+ return x;
+}
+
+static lua_Number LoadNumber(LoadState* S)
+{
+ lua_Number x;
+ LoadVar(S,x);
+ return x;
+}
+
+static TString* LoadString(LoadState* S)
+{
+ size_t size;
+ LoadVar(S,size);
+ if (size==0)
+  return NULL;
+ else
+ {
+  char* s=luaZ_openspace(S->L,S->b,size);
+  LoadBlock(S,s,size);
+  return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */
+ }
+}
+
+static void LoadCode(LoadState* S, Proto* f)
+{
+ int n=LoadInt(S);
+ f->code=luaM_newvector(S->L,n,Instruction);
+ f->sizecode=n;
+ LoadVector(S,f->code,n,sizeof(Instruction));
+}
+
+static Proto* LoadFunction(LoadState* S, TString* p);
+
+static void LoadConstants(LoadState* S, Proto* f)
+{
+ int i,n;
+ n=LoadInt(S);
+ f->k=luaM_newvector(S->L,n,TValue);
+ f->sizek=n;
+ for (i=0; i<n; i++) setnilvalue(&f->k[i]);
+ for (i=0; i<n; i++)
+ {
+  TValue* o=&f->k[i];
+  int t=LoadChar(S);
+  switch (t)
+  {
+   case LUA_TNIL:
+   	setnilvalue(o);
+	break;
+   case LUA_TBOOLEAN:
+   	setbvalue(o,LoadChar(S));
+	break;
+   case LUA_TNUMBER:
+	setnvalue(o,LoadNumber(S));
+	break;
+   case LUA_TSTRING:
+	setsvalue2n(S->L,o,LoadString(S));
+	break;
+   default:
+	error(S,"bad constant");
+	break;
+  }
+ }
+ n=LoadInt(S);
+ f->p=luaM_newvector(S->L,n,Proto*);
+ f->sizep=n;
+ for (i=0; i<n; i++) f->p[i]=NULL;
+ for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
+}
+
+static void LoadDebug(LoadState* S, Proto* f)
+{
+ int i,n;
+ n=LoadInt(S);
+ f->lineinfo=luaM_newvector(S->L,n,int);
+ f->sizelineinfo=n;
+ LoadVector(S,f->lineinfo,n,sizeof(int));
+ n=LoadInt(S);
+ f->locvars=luaM_newvector(S->L,n,LocVar);
+ f->sizelocvars=n;
+ for (i=0; i<n; i++) f->locvars[i].varname=NULL;
+ for (i=0; i<n; i++)
+ {
+  f->locvars[i].varname=LoadString(S);
+  f->locvars[i].startpc=LoadInt(S);
+  f->locvars[i].endpc=LoadInt(S);
+ }
+ n=LoadInt(S);
+ f->upvalues=luaM_newvector(S->L,n,TString*);
+ f->sizeupvalues=n;
+ for (i=0; i<n; i++) f->upvalues[i]=NULL;
+ for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
+}
+
+static Proto* LoadFunction(LoadState* S, TString* p)
+{
+ Proto* f=luaF_newproto(S->L);
+ setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
+ f->source=LoadString(S); if (f->source==NULL) f->source=p;
+ f->linedefined=LoadInt(S);
+ f->lastlinedefined=LoadInt(S);
+ f->nups=LoadByte(S);
+ f->numparams=LoadByte(S);
+ f->is_vararg=LoadByte(S);
+ f->maxstacksize=LoadByte(S);
+ LoadCode(S,f);
+ LoadConstants(S,f);
+ LoadDebug(S,f);
+ IF (!luaG_checkcode(f), "bad code");
+ S->L->top--;
+ return f;
+}
+
+static void LoadHeader(LoadState* S)
+{
+ char h[LUAC_HEADERSIZE];
+ char s[LUAC_HEADERSIZE];
+ luaU_header(h);
+ LoadBlock(S,s,LUAC_HEADERSIZE);
+ IF (memcmp(h,s,LUAC_HEADERSIZE)!=0, "bad header");
+}
+
+/*
+** load precompiled chunk
+*/
+Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
+{
+ LoadState S;
+ if (*name=='@' || *name=='=')
+  S.name=name+1;
+ else if (*name==LUA_SIGNATURE[0])
+  S.name="binary string";
+ else
+  S.name=name;
+ S.L=L;
+ S.Z=Z;
+ S.b=buff;
+ LoadHeader(&S);
+ return LoadFunction(&S,luaS_newliteral(L,"=?"));
+}
+
+/*
+* make header
+*/
+void luaU_header (char* h)
+{
+ int x=1;
+ memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
+ h+=sizeof(LUA_SIGNATURE)-1;
+ *h++=(char)LUAC_VERSION;
+ *h++=(char)LUAC_FORMAT;
+ *h++=(char)*(char*)&x;				/* endianness */
+ *h++=(char)sizeof(int);
+ *h++=(char)sizeof(size_t);
+ *h++=(char)sizeof(Instruction);
+ *h++=(char)sizeof(lua_Number);
+ *h++=(char)(((lua_Number)0.5)==0);		/* is lua_Number integral? */
+}

=== added file 'lua/lundump.h'
--- lua/lundump.h	1970-01-01 00:00:00 +0000
+++ lua/lundump.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,36 @@
+/*
+** $Id: lundump.h,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lundump_h
+#define lundump_h
+
+#include "lobject.h"
+#include "lzio.h"
+
+/* load one chunk; from lundump.c */
+LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
+
+/* make header; from lundump.c */
+LUAI_FUNC void luaU_header (char* h);
+
+/* dump one chunk; from ldump.c */
+LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
+
+#ifdef luac_c
+/* print one chunk; from print.c */
+LUAI_FUNC void luaU_print (const Proto* f, int full);
+#endif
+
+/* for header of binary files -- this is Lua 5.1 */
+#define LUAC_VERSION		0x51
+
+/* for header of binary files -- this is the official format */
+#define LUAC_FORMAT		0
+
+/* size of header of binary files */
+#define LUAC_HEADERSIZE		12
+
+#endif

=== added file 'lua/lvm.c'
--- lua/lvm.c	1970-01-01 00:00:00 +0000
+++ lua/lvm.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,784 @@
+/*
+** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lvm_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lgc.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "ltm.h"
+#include "lvm.h"
+
+
+#if defined LUA_NUMBER_INTEGRAL
+LUA_NUMBER luai_ipow(LUA_NUMBER a, LUA_NUMBER b) {
+  if (b < 0)
+    return 0;
+  else if (b == 0)
+    return 1;
+  else {
+    LUA_NUMBER c = 1;
+    for (;;) {
+      if (b & 1)
+	c *= a;
+      b = b >> 1;
+      if (b == 0)
+	return c;
+      a *= a;
+    }
+  }
+}
+#endif
+
+/* limit for table tag-method chains (to avoid loops) */
+#define MAXTAGLOOP	100
+
+
+const TValue *luaV_tonumber (const TValue *obj, TValue *n) {
+  lua_Number num;
+  if (ttisnumber(obj)) return obj;
+  if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) {
+    setnvalue(n, num);
+    return n;
+  }
+  else
+    return NULL;
+}
+
+
+int luaV_tostring (lua_State *L, StkId obj) {
+  if (!ttisnumber(obj))
+    return 0;
+  else {
+    char s[LUAI_MAXNUMBER2STR];
+    lua_Number n = nvalue(obj);
+    lua_number2str(s, n);
+    setsvalue2s(L, obj, luaS_new(L, s));
+    return 1;
+  }
+}
+
+
+static void traceexec (lua_State *L, const Instruction *pc) {
+  lu_byte mask = L->hookmask;
+  const Instruction *oldpc = L->savedpc;
+  L->savedpc = pc;
+  if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
+    resethookcount(L);
+    luaD_callhook(L, LUA_HOOKCOUNT, -1);
+  }
+  if (mask & LUA_MASKLINE) {
+    Proto *p = ci_func(L->ci)->l.p;
+    int npc = pcRel(pc, p);
+    int newline = getline(p, npc);
+    /* call linehook when enter a new function, when jump back (loop),
+       or when enter a new line */
+    if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p)))
+      luaD_callhook(L, LUA_HOOKLINE, newline);
+  }
+}
+
+
+static void callTMres (lua_State *L, StkId res, const TValue *f,
+                        const TValue *p1, const TValue *p2) {
+  ptrdiff_t result = savestack(L, res);
+  setobj2s(L, L->top, f);  /* push function */
+  setobj2s(L, L->top+1, p1);  /* 1st argument */
+  setobj2s(L, L->top+2, p2);  /* 2nd argument */
+  luaD_checkstack(L, 3);
+  L->top += 3;
+  luaD_call(L, L->top - 3, 1);
+  res = restorestack(L, result);
+  L->top--;
+  setobjs2s(L, res, L->top);
+}
+
+
+
+static void callTM (lua_State *L, const TValue *f, const TValue *p1,
+                    const TValue *p2, const TValue *p3) {
+  setobj2s(L, L->top, f);  /* push function */
+  setobj2s(L, L->top+1, p1);  /* 1st argument */
+  setobj2s(L, L->top+2, p2);  /* 2nd argument */
+  setobj2s(L, L->top+3, p3);  /* 3th argument */
+  luaD_checkstack(L, 4);
+  L->top += 4;
+  luaD_call(L, L->top - 4, 0);
+}
+
+
+void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+  int loop;
+  for (loop = 0; loop < MAXTAGLOOP; loop++) {
+    const TValue *tm;
+    if (ttistable(t)) {  /* `t' is a table? */
+      Table *h = hvalue(t);
+      const TValue *res = luaH_get(h, key); /* do a primitive get */
+      if (!ttisnil(res) ||  /* result is no nil? */
+          (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
+        setobj2s(L, val, res);
+        return;
+      }
+      /* else will try the tag method */
+    }
+    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
+      luaG_typeerror(L, t, "index");
+    if (ttisfunction(tm)) {
+      callTMres(L, val, tm, t, key);
+      return;
+    }
+    t = tm;  /* else repeat with `tm' */ 
+  }
+  luaG_runerror(L, "loop in gettable");
+}
+
+
+void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+  int loop;
+  for (loop = 0; loop < MAXTAGLOOP; loop++) {
+    const TValue *tm;
+    if (ttistable(t)) {  /* `t' is a table? */
+      Table *h = hvalue(t);
+      TValue *oldval = luaH_set(L, h, key); /* do a primitive set */
+      if (!ttisnil(oldval) ||  /* result is no nil? */
+          (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
+        setobj2t(L, oldval, val);
+        luaC_barriert(L, h, val);
+        return;
+      }
+      /* else will try the tag method */
+    }
+    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
+      luaG_typeerror(L, t, "index");
+    if (ttisfunction(tm)) {
+      callTM(L, tm, t, key, val);
+      return;
+    }
+    t = tm;  /* else repeat with `tm' */ 
+  }
+  luaG_runerror(L, "loop in settable");
+}
+
+
+static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2,
+                       StkId res, TMS event) {
+  const TValue *tm = luaT_gettmbyobj(L, p1, event);  /* try first operand */
+  if (ttisnil(tm))
+    tm = luaT_gettmbyobj(L, p2, event);  /* try second operand */
+  if (ttisnil(tm)) return 0;
+  callTMres(L, res, tm, p1, p2);
+  return 1;
+}
+
+
+static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2,
+                                  TMS event) {
+  const TValue *tm1 = fasttm(L, mt1, event);
+  const TValue *tm2;
+  if (tm1 == NULL) return NULL;  /* no metamethod */
+  if (mt1 == mt2) return tm1;  /* same metatables => same metamethods */
+  tm2 = fasttm(L, mt2, event);
+  if (tm2 == NULL) return NULL;  /* no metamethod */
+  if (luaO_rawequalObj(tm1, tm2))  /* same metamethods? */
+    return tm1;
+  return NULL;
+}
+
+
+static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2,
+                         TMS event) {
+  const TValue *tm1 = luaT_gettmbyobj(L, p1, event);
+  const TValue *tm2;
+  if (ttisnil(tm1)) return -1;  /* no metamethod? */
+  tm2 = luaT_gettmbyobj(L, p2, event);
+  if (!luaO_rawequalObj(tm1, tm2))  /* different metamethods? */
+    return -1;
+  callTMres(L, L->top, tm1, p1, p2);
+  return !l_isfalse(L->top);
+}
+
+
+static int l_strcmp (const TString *ls, const TString *rs) {
+  const char *l = getstr(ls);
+  size_t ll = ls->tsv.len;
+  const char *r = getstr(rs);
+  size_t lr = rs->tsv.len;
+  for (;;) {
+    int temp = strcoll(l, r);
+    if (temp != 0) return temp;
+    else {  /* strings are equal up to a `\0' */
+      size_t len = strlen(l);  /* index of first `\0' in both strings */
+      if (len == lr)  /* r is finished? */
+        return (len == ll) ? 0 : 1;
+      else if (len == ll)  /* l is finished? */
+        return -1;  /* l is smaller than r (because r is not finished) */
+      /* both strings longer than `len'; go on comparing (after the `\0') */
+      len++;
+      l += len; ll -= len; r += len; lr -= len;
+    }
+  }
+}
+
+
+int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
+  int res;
+  if (ttype(l) != ttype(r))
+    return luaG_ordererror(L, l, r);
+  else if (ttisnumber(l))
+    return luai_numlt(nvalue(l), nvalue(r));
+  else if (ttisstring(l))
+    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
+  else if ((res = call_orderTM(L, l, r, TM_LT)) != -1)
+    return res;
+  return luaG_ordererror(L, l, r);
+}
+
+
+static int lessequal (lua_State *L, const TValue *l, const TValue *r) {
+  int res;
+  if (ttype(l) != ttype(r))
+    return luaG_ordererror(L, l, r);
+  else if (ttisnumber(l))
+    return luai_numle(nvalue(l), nvalue(r));
+  else if (ttisstring(l))
+    return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
+  else if ((res = call_orderTM(L, l, r, TM_LE)) != -1)  /* first try `le' */
+    return res;
+  else if ((res = call_orderTM(L, r, l, TM_LT)) != -1)  /* else try `lt' */
+    return !res;
+  return luaG_ordererror(L, l, r);
+}
+
+
+int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) {
+  const TValue *tm;
+  lua_assert(ttype(t1) == ttype(t2));
+  switch (ttype(t1)) {
+    case LUA_TNIL: return 1;
+    case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2));
+    case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2);  /* true must be 1 !! */
+    case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
+    case LUA_TUSERDATA: {
+      if (uvalue(t1) == uvalue(t2)) return 1;
+      tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable,
+                         TM_EQ);
+      break;  /* will try TM */
+    }
+    case LUA_TTABLE: {
+      if (hvalue(t1) == hvalue(t2)) return 1;
+      tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ);
+      break;  /* will try TM */
+    }
+    default: return gcvalue(t1) == gcvalue(t2);
+  }
+  if (tm == NULL) return 0;  /* no TM? */
+  callTMres(L, L->top, tm, t1, t2);  /* call TM */
+  return !l_isfalse(L->top);
+}
+
+
+void luaV_concat (lua_State *L, int total, int last) {
+  do {
+    StkId top = L->base + last + 1;
+    int n = 2;  /* number of elements handled in this pass (at least 2) */
+    if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
+      if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
+        luaG_concaterror(L, top-2, top-1);
+    } else if (tsvalue(top-1)->len == 0)  /* second op is empty? */
+      (void)tostring(L, top - 2);  /* result is first op (as string) */
+    else {
+      /* at least two string values; get as many as possible */
+      size_t tl = tsvalue(top-1)->len;
+      char *buffer;
+      int i;
+      /* collect total length */
+      for (n = 1; n < total && tostring(L, top-n-1); n++) {
+        size_t l = tsvalue(top-n-1)->len;
+        if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
+        tl += l;
+      }
+      buffer = luaZ_openspace(L, &G(L)->buff, tl);
+      tl = 0;
+      for (i=n; i>0; i--) {  /* concat all strings */
+        size_t l = tsvalue(top-i)->len;
+        memcpy(buffer+tl, svalue(top-i), l);
+        tl += l;
+      }
+      setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
+    }
+    total -= n-1;  /* got `n' strings to create 1 new */
+    last -= n-1;
+  } while (total > 1);  /* repeat until only 1 result left */
+}
+
+
+static void Arith (lua_State *L, StkId ra, const TValue *rb,
+                   const TValue *rc, TMS op) {
+  TValue tempb, tempc;
+  const TValue *b, *c;
+  if ((b = luaV_tonumber(rb, &tempb)) != NULL &&
+      (c = luaV_tonumber(rc, &tempc)) != NULL) {
+    lua_Number nb = nvalue(b), nc = nvalue(c);
+    switch (op) {
+      case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
+      case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
+      case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
+      case TM_DIV: setnvalue(ra, luai_lnumdiv(nb, nc)); break;
+      case TM_MOD: setnvalue(ra, luai_lnummod(nb, nc)); break;
+      case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
+      case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
+      default: lua_assert(0); break;
+    }
+  }
+  else if (!call_binTM(L, rb, rc, ra, op))
+    luaG_aritherror(L, rb, rc);
+}
+
+
+
+/*
+** some macros for common tasks in `luaV_execute'
+*/
+
+#define runtime_check(L, c)	{ if (!(c)) break; }
+
+#define RA(i)	(base+GETARG_A(i))
+/* to be used after possible stack reallocation */
+#define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
+#define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
+#define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
+	ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
+#define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
+	ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
+#define KBx(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i))
+
+
+#define dojump(L,pc,i)	{(pc) += (i); luai_threadyield(L);}
+
+
+#define Protect(x)	{ L->savedpc = pc; {x;}; base = L->base; }
+
+
+#define arith_op(op,tm) { \
+        TValue *rb = RKB(i); \
+        TValue *rc = RKC(i); \
+        if (ttisnumber(rb) && ttisnumber(rc)) { \
+          lua_Number nb = nvalue(rb), nc = nvalue(rc); \
+          setnvalue(ra, op(nb, nc)); \
+        } \
+        else \
+          Protect(Arith(L, ra, rb, rc, tm)); \
+      }
+
+
+
+void luaV_execute (lua_State *L, int nexeccalls) {
+  LClosure *cl;
+  StkId base;
+  TValue *k;
+  const Instruction *pc;
+ reentry:  /* entry point */
+  lua_assert(isLua(L->ci));
+  pc = L->savedpc;
+  cl = &clvalue(L->ci->func)->l;
+  base = L->base;
+  k = cl->p->k;
+  /* main loop of interpreter */
+  for (;;) {
+    const Instruction i = *pc++;
+    StkId ra;
+    if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
+        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
+      traceexec(L, pc);
+      if (L->status == LUA_YIELD) {  /* did hook yield? */
+        L->savedpc = pc - 1;
+        return;
+      }
+      base = L->base;
+    }
+    /* warning!! several calls may realloc the stack and invalidate `ra' */
+    ra = RA(i);
+    lua_assert(base == L->base && L->base == L->ci->base);
+    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
+    lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
+    switch (GET_OPCODE(i)) {
+      case OP_MOVE: {
+        setobjs2s(L, ra, RB(i));
+        continue;
+      }
+      case OP_LOADK: {
+        setobj2s(L, ra, KBx(i));
+        continue;
+      }
+      case OP_LOADBOOL: {
+        setbvalue(ra, GETARG_B(i));
+        if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */
+        continue;
+      }
+      case OP_LOADNIL: {
+        TValue *rb = RB(i);
+        do {
+          setnilvalue(rb--);
+        } while (rb >= ra);
+        continue;
+      }
+      case OP_GETUPVAL: {
+        int b = GETARG_B(i);
+        setobj2s(L, ra, cl->upvals[b]->v);
+        continue;
+      }
+      case OP_GETGLOBAL: {
+        TValue g;
+        TValue *rb = KBx(i);
+        sethvalue(L, &g, cl->env);
+        lua_assert(ttisstring(rb));
+        Protect(luaV_gettable(L, &g, rb, ra));
+        continue;
+      }
+      case OP_GETTABLE: {
+        Protect(luaV_gettable(L, RB(i), RKC(i), ra));
+        continue;
+      }
+      case OP_SETGLOBAL: {
+        TValue g;
+        sethvalue(L, &g, cl->env);
+        lua_assert(ttisstring(KBx(i)));
+        Protect(luaV_settable(L, &g, KBx(i), ra));
+        continue;
+      }
+      case OP_SETUPVAL: {
+        UpVal *uv = cl->upvals[GETARG_B(i)];
+        setobj(L, uv->v, ra);
+        luaC_barrier(L, uv, ra);
+        continue;
+      }
+      case OP_SETTABLE: {
+        Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
+        continue;
+      }
+      case OP_NEWTABLE: {
+        int b = GETARG_B(i);
+        int c = GETARG_C(i);
+        sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
+        Protect(luaC_checkGC(L));
+        continue;
+      }
+      case OP_SELF: {
+        StkId rb = RB(i);
+        setobjs2s(L, ra+1, rb);
+        Protect(luaV_gettable(L, rb, RKC(i), ra));
+        continue;
+      }
+      case OP_ADD: {
+        arith_op(luai_numadd, TM_ADD);
+        continue;
+      }
+      case OP_SUB: {
+        arith_op(luai_numsub, TM_SUB);
+        continue;
+      }
+      case OP_MUL: {
+        arith_op(luai_nummul, TM_MUL);
+        continue;
+      }
+      case OP_DIV: {
+        arith_op(luai_lnumdiv, TM_DIV);
+        continue;
+      }
+      case OP_MOD: {
+        arith_op(luai_lnummod, TM_MOD);
+        continue;
+      }
+      case OP_POW: {
+        arith_op(luai_numpow, TM_POW);
+        continue;
+      }
+      case OP_UNM: {
+        TValue *rb = RB(i);
+        if (ttisnumber(rb)) {
+          lua_Number nb = nvalue(rb);
+          setnvalue(ra, luai_numunm(nb));
+        }
+        else {
+          Protect(Arith(L, ra, rb, rb, TM_UNM));
+        }
+        continue;
+      }
+      case OP_NOT: {
+        int res = l_isfalse(RB(i));  /* next assignment may change this value */
+        setbvalue(ra, res);
+        continue;
+      }
+      case OP_LEN: {
+        const TValue *rb = RB(i);
+        switch (ttype(rb)) {
+          case LUA_TTABLE: {
+            setnvalue(ra, cast_num(luaH_getn(hvalue(rb))));
+            break;
+          }
+          case LUA_TSTRING: {
+            setnvalue(ra, cast_num(tsvalue(rb)->len));
+            break;
+          }
+          default: {  /* try metamethod */
+            Protect(
+              if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN))
+                luaG_typeerror(L, rb, "get length of");
+            )
+          }
+        }
+        continue;
+      }
+      case OP_CONCAT: {
+        int b = GETARG_B(i);
+        int c = GETARG_C(i);
+        Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L));
+        setobjs2s(L, RA(i), base+b);
+        continue;
+      }
+      case OP_JMP: {
+        dojump(L, pc, GETARG_sBx(i));
+        continue;
+      }
+      case OP_EQ: {
+        TValue *rb = RKB(i);
+        TValue *rc = RKC(i);
+        Protect(
+          if (equalobj(L, rb, rc) == GETARG_A(i))
+            dojump(L, pc, GETARG_sBx(*pc));
+        )
+        pc++;
+        continue;
+      }
+      case OP_LT: {
+        Protect(
+          if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
+            dojump(L, pc, GETARG_sBx(*pc));
+        )
+        pc++;
+        continue;
+      }
+      case OP_LE: {
+        Protect(
+          if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
+            dojump(L, pc, GETARG_sBx(*pc));
+        )
+        pc++;
+        continue;
+      }
+      case OP_TEST: {
+        if (l_isfalse(ra) != GETARG_C(i))
+          dojump(L, pc, GETARG_sBx(*pc));
+        pc++;
+        continue;
+      }
+      case OP_TESTSET: {
+        TValue *rb = RB(i);
+        if (l_isfalse(rb) != GETARG_C(i)) {
+          setobjs2s(L, ra, rb);
+          dojump(L, pc, GETARG_sBx(*pc));
+        }
+        pc++;
+        continue;
+      }
+      case OP_CALL: {
+        int b = GETARG_B(i);
+        int nresults = GETARG_C(i) - 1;
+        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+        L->savedpc = pc;
+        switch (luaD_precall(L, ra, nresults)) {
+          case PCRLUA: {
+            nexeccalls++;
+            goto reentry;  /* restart luaV_execute over new Lua function */
+          }
+          case PCRC: {
+            /* it was a C function (`precall' called it); adjust results */
+            if (nresults >= 0) L->top = L->ci->top;
+            base = L->base;
+            continue;
+          }
+          default: {
+            return;  /* yield */
+          }
+        }
+      }
+      case OP_TAILCALL: {
+        int b = GETARG_B(i);
+        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+        L->savedpc = pc;
+        lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
+        switch (luaD_precall(L, ra, LUA_MULTRET)) {
+          case PCRLUA: {
+            /* tail call: put new frame in place of previous one */
+            CallInfo *ci = L->ci - 1;  /* previous frame */
+            int aux;
+            StkId func = ci->func;
+            StkId pfunc = (ci+1)->func;  /* previous function index */
+            if (L->openupval) luaF_close(L, ci->base);
+            L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
+            for (aux = 0; pfunc+aux < L->top; aux++)  /* move frame down */
+              setobjs2s(L, func+aux, pfunc+aux);
+            ci->top = L->top = func+aux;  /* correct top */
+            lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
+            ci->savedpc = L->savedpc;
+            ci->tailcalls++;  /* one more call lost */
+            L->ci--;  /* remove new frame */
+            goto reentry;
+          }
+          case PCRC: {  /* it was a C function (`precall' called it) */
+            base = L->base;
+            continue;
+          }
+          default: {
+            return;  /* yield */
+          }
+        }
+      }
+      case OP_RETURN: {
+        int b = GETARG_B(i);
+        if (b != 0) L->top = ra+b-1;
+        if (L->openupval) luaF_close(L, base);
+        L->savedpc = pc;
+        b = luaD_poscall(L, ra);
+        if (--nexeccalls == 0)  /* was previous function running `here'? */
+          return;  /* no: return */
+        else {  /* yes: continue its execution */
+          if (b) L->top = L->ci->top;
+          lua_assert(isLua(L->ci));
+          lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL);
+          goto reentry;
+        }
+      }
+      case OP_FORLOOP: {
+        lua_Number step = nvalue(ra+2);
+        lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */
+        lua_Number limit = nvalue(ra+1);
+        if (luai_numlt(0, step) ? luai_numle(idx, limit)
+                                : luai_numle(limit, idx)) {
+          dojump(L, pc, GETARG_sBx(i));  /* jump back */
+          setnvalue(ra, idx);  /* update internal index... */
+          setnvalue(ra+3, idx);  /* ...and external index */
+        }
+        continue;
+      }
+      case OP_FORPREP: {
+        const TValue *init = ra;
+        const TValue *plimit = ra+1;
+        const TValue *pstep = ra+2;
+        L->savedpc = pc;  /* next steps may throw errors */
+        if (!tonumber(init, ra))
+          luaG_runerror(L, LUA_QL("for") " initial value must be a number");
+        else if (!tonumber(plimit, ra+1))
+          luaG_runerror(L, LUA_QL("for") " limit must be a number");
+        else if (!tonumber(pstep, ra+2))
+          luaG_runerror(L, LUA_QL("for") " step must be a number");
+        setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
+        dojump(L, pc, GETARG_sBx(i));
+        continue;
+      }
+      case OP_TFORLOOP: {
+        StkId cb = ra + 3;  /* call base */
+        setobjs2s(L, cb+2, ra+2);
+        setobjs2s(L, cb+1, ra+1);
+        setobjs2s(L, cb, ra);
+        L->top = cb+3;  /* func. + 2 args (state and index) */
+        Protect(luaD_call(L, cb, GETARG_C(i)));
+        L->top = L->ci->top;
+        cb = RA(i) + 3;  /* previous call may change the stack */
+        if (!ttisnil(cb)) {  /* continue loop? */
+          setobjs2s(L, cb-1, cb);  /* save control variable */
+          dojump(L, pc, GETARG_sBx(*pc));  /* jump back */
+        }
+        pc++;
+        continue;
+      }
+      case OP_SETLIST: {
+        int n = GETARG_B(i);
+        int c = GETARG_C(i);
+        int last;
+        Table *h;
+        if (n == 0) {
+          n = cast_int(L->top - ra) - 1;
+          L->top = L->ci->top;
+        }
+        if (c == 0) c = cast_int(*pc++);
+        runtime_check(L, ttistable(ra));
+        h = hvalue(ra);
+        last = ((c-1)*LFIELDS_PER_FLUSH) + n;
+        if (last > h->sizearray)  /* needs more space? */
+          luaH_resizearray(L, h, last);  /* pre-alloc it at once */
+        for (; n > 0; n--) {
+          TValue *val = ra+n;
+          setobj2t(L, luaH_setnum(L, h, last--), val);
+          luaC_barriert(L, h, val);
+        }
+        continue;
+      }
+      case OP_CLOSE: {
+        luaF_close(L, ra);
+        continue;
+      }
+      case OP_CLOSURE: {
+        Proto *p;
+        Closure *ncl;
+        int nup, j;
+        p = cl->p->p[GETARG_Bx(i)];
+        nup = p->nups;
+        ncl = luaF_newLclosure(L, nup, cl->env);
+        ncl->l.p = p;
+        for (j=0; j<nup; j++, pc++) {
+          if (GET_OPCODE(*pc) == OP_GETUPVAL)
+            ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)];
+          else {
+            lua_assert(GET_OPCODE(*pc) == OP_MOVE);
+            ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc));
+          }
+        }
+        setclvalue(L, ra, ncl);
+        Protect(luaC_checkGC(L));
+        continue;
+      }
+      case OP_VARARG: {
+        int b = GETARG_B(i) - 1;
+        int j;
+        CallInfo *ci = L->ci;
+        int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1;
+        if (b == LUA_MULTRET) {
+          Protect(luaD_checkstack(L, n));
+          ra = RA(i);  /* previous call may change the stack */
+          b = n;
+          L->top = ra + n;
+        }
+        for (j = 0; j < b; j++) {
+          if (j < n) {
+            setobjs2s(L, ra + j, ci->base - n + j);
+          }
+          else {
+            setnilvalue(ra + j);
+          }
+        }
+        continue;
+      }
+    }
+  }
+}
+

=== added file 'lua/lvm.h'
--- lua/lvm.h	1970-01-01 00:00:00 +0000
+++ lua/lvm.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,36 @@
+/*
+** $Id: lvm.h,v 2.5.1.1 2007/12/27 13:02:25 roberto Exp $
+** Lua virtual machine
+** See Copyright Notice in lua.h
+*/
+
+#ifndef lvm_h
+#define lvm_h
+
+
+#include "ldo.h"
+#include "lobject.h"
+#include "ltm.h"
+
+
+#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
+
+#define tonumber(o,n)	(ttype(o) == LUA_TNUMBER || \
+                         (((o) = luaV_tonumber(o,n)) != NULL))
+
+#define equalobj(L,o1,o2) \
+	(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
+
+
+LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
+LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2);
+LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
+LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
+LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
+                                            StkId val);
+LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
+                                            StkId val);
+LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls);
+LUAI_FUNC void luaV_concat (lua_State *L, int total, int last);
+
+#endif

=== added file 'lua/lzio.c'
--- lua/lzio.c	1970-01-01 00:00:00 +0000
+++ lua/lzio.c	2008-08-01 15:27:27 +0000
@@ -0,0 +1,84 @@
+/*
+** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $
+** a generic input stream interface
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef USE_GRUB_LIB
+#include <string.h>
+#endif /* ! USE_GRUB_LIB */
+
+#define lzio_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "llimits.h"
+#include "lmem.h"
+#include "lstate.h"
+#include "lzio.h"
+
+
+int luaZ_fill (ZIO *z) {
+  size_t size;
+  lua_State *L = z->L;
+  const char *buff;
+  lua_unlock(L);
+  buff = z->reader(L, z->data, &size);
+  lua_lock(L);
+  if (buff == NULL || size == 0) return EOZ;
+  z->n = size - 1;
+  z->p = buff;
+  return char2int(*(z->p++));
+}
+
+
+int luaZ_lookahead (ZIO *z) {
+  if (z->n == 0) {
+    if (luaZ_fill(z) == EOZ)
+      return EOZ;
+    else {
+      z->n++;  /* luaZ_fill removed first byte; put back it */
+      z->p--;
+    }
+  }
+  return char2int(*z->p);
+}
+
+
+void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
+  z->L = L;
+  z->reader = reader;
+  z->data = data;
+  z->n = 0;
+  z->p = NULL;
+}
+
+
+/* --------------------------------------------------------------- read --- */
+size_t luaZ_read (ZIO *z, void *b, size_t n) {
+  while (n) {
+    size_t m;
+    if (luaZ_lookahead(z) == EOZ)
+      return n;  /* return number of missing bytes */
+    m = (n <= z->n) ? n : z->n;  /* min. between n and z->n */
+    memcpy(b, z->p, m);
+    z->n -= m;
+    z->p += m;
+    b = (char *)b + m;
+    n -= m;
+  }
+  return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
+  if (n > buff->buffsize) {
+    if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
+    luaZ_resizebuffer(L, buff, n);
+  }
+  return buff->buffer;
+}
+
+

=== added file 'lua/lzio.h'
--- lua/lzio.h	1970-01-01 00:00:00 +0000
+++ lua/lzio.h	2008-08-01 15:19:23 +0000
@@ -0,0 +1,67 @@
+/*
+** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $
+** Buffered streams
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lzio_h
+#define lzio_h
+
+#include "lua.h"
+
+#include "lmem.h"
+
+
+#define EOZ	(-1)			/* end of stream */
+
+typedef struct Zio ZIO;
+
+#define char2int(c)	cast(int, cast(unsigned char, (c)))
+
+#define zgetc(z)  (((z)->n--)>0 ?  char2int(*(z)->p++) : luaZ_fill(z))
+
+typedef struct Mbuffer {
+  char *buffer;
+  size_t n;
+  size_t buffsize;
+} Mbuffer;
+
+#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
+
+#define luaZ_buffer(buff)	((buff)->buffer)
+#define luaZ_sizebuffer(buff)	((buff)->buffsize)
+#define luaZ_bufflen(buff)	((buff)->n)
+
+#define luaZ_resetbuffer(buff) ((buff)->n = 0)
+
+
+#define luaZ_resizebuffer(L, buff, size) \
+	(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
+	(buff)->buffsize = size)
+
+#define luaZ_freebuffer(L, buff)	luaZ_resizebuffer(L, buff, 0)
+
+
+LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
+LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
+                                        void *data);
+LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n);	/* read next n bytes */
+LUAI_FUNC int luaZ_lookahead (ZIO *z);
+
+
+
+/* --------- Private Part ------------------ */
+
+struct Zio {
+  size_t n;			/* bytes still unread */
+  const char *p;		/* current position in buffer */
+  lua_Reader reader;
+  void* data;			/* additional data */
+  lua_State *L;			/* Lua state (for reader) */
+};
+
+
+LUAI_FUNC int luaZ_fill (ZIO *z);
+
+#endif

=== added file 'lua/print.c'
--- lua/print.c	1970-01-01 00:00:00 +0000
+++ lua/print.c	2008-08-01 15:19:23 +0000
@@ -0,0 +1,227 @@
+/*
+** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $
+** print bytecodes
+** See Copyright Notice in lua.h
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+
+#define luac_c
+#define LUA_CORE
+
+#include "ldebug.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lundump.h"
+
+#define PrintFunction	luaU_print
+
+#define Sizeof(x)	((int)sizeof(x))
+#define VOID(p)		((const void*)(p))
+
+static void PrintString(const TString* ts)
+{
+ const char* s=getstr(ts);
+ size_t i,n=ts->tsv.len;
+ putchar('"');
+ for (i=0; i<n; i++)
+ {
+  int c=s[i];
+  switch (c)
+  {
+   case '"': printf("\\\""); break;
+   case '\\': printf("\\\\"); break;
+   case '\a': printf("\\a"); break;
+   case '\b': printf("\\b"); break;
+   case '\f': printf("\\f"); break;
+   case '\n': printf("\\n"); break;
+   case '\r': printf("\\r"); break;
+   case '\t': printf("\\t"); break;
+   case '\v': printf("\\v"); break;
+   default:	if (isprint((unsigned char)c))
+   			putchar(c);
+		else
+			printf("\\%03u",(unsigned char)c);
+  }
+ }
+ putchar('"');
+}
+
+static void PrintConstant(const Proto* f, int i)
+{
+ const TValue* o=&f->k[i];
+ switch (ttype(o))
+ {
+  case LUA_TNIL:
+	printf("nil");
+	break;
+  case LUA_TBOOLEAN:
+	printf(bvalue(o) ? "true" : "false");
+	break;
+  case LUA_TNUMBER:
+	printf(LUA_NUMBER_FMT,nvalue(o));
+	break;
+  case LUA_TSTRING:
+	PrintString(rawtsvalue(o));
+	break;
+  default:				/* cannot happen */
+	printf("? type=%d",ttype(o));
+	break;
+ }
+}
+
+static void PrintCode(const Proto* f)
+{
+ const Instruction* code=f->code;
+ int pc,n=f->sizecode;
+ for (pc=0; pc<n; pc++)
+ {
+  Instruction i=code[pc];
+  OpCode o=GET_OPCODE(i);
+  int a=GETARG_A(i);
+  int b=GETARG_B(i);
+  int c=GETARG_C(i);
+  int bx=GETARG_Bx(i);
+  int sbx=GETARG_sBx(i);
+  int line=getline(f,pc);
+  printf("\t%d\t",pc+1);
+  if (line>0) printf("[%d]\t",line); else printf("[-]\t");
+  printf("%-9s\t",luaP_opnames[o]);
+  switch (getOpMode(o))
+  {
+   case iABC:
+    printf("%d",a);
+    if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (-1-INDEXK(b)) : b);
+    if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (-1-INDEXK(c)) : c);
+    break;
+   case iABx:
+    if (getBMode(o)==OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx);
+    break;
+   case iAsBx:
+    if (o==OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx);
+    break;
+  }
+  switch (o)
+  {
+   case OP_LOADK:
+    printf("\t; "); PrintConstant(f,bx);
+    break;
+   case OP_GETUPVAL:
+   case OP_SETUPVAL:
+    printf("\t; %s", (f->sizeupvalues>0) ? getstr(f->upvalues[b]) : "-");
+    break;
+   case OP_GETGLOBAL:
+   case OP_SETGLOBAL:
+    printf("\t; %s",svalue(&f->k[bx]));
+    break;
+   case OP_GETTABLE:
+   case OP_SELF:
+    if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
+    break;
+   case OP_SETTABLE:
+   case OP_ADD:
+   case OP_SUB:
+   case OP_MUL:
+   case OP_DIV:
+   case OP_POW:
+   case OP_EQ:
+   case OP_LT:
+   case OP_LE:
+    if (ISK(b) || ISK(c))
+    {
+     printf("\t; ");
+     if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
+     printf(" ");
+     if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
+    }
+    break;
+   case OP_JMP:
+   case OP_FORLOOP:
+   case OP_FORPREP:
+    printf("\t; to %d",sbx+pc+2);
+    break;
+   case OP_CLOSURE:
+    printf("\t; %p",VOID(f->p[bx]));
+    break;
+   case OP_SETLIST:
+    if (c==0) printf("\t; %d",(int)code[++pc]);
+    else printf("\t; %d",c);
+    break;
+   default:
+    break;
+  }
+  printf("\n");
+ }
+}
+
+#define SS(x)	(x==1)?"":"s"
+#define S(x)	x,SS(x)
+
+static void PrintHeader(const Proto* f)
+{
+ const char* s=getstr(f->source);
+ if (*s=='@' || *s=='=')
+  s++;
+ else if (*s==LUA_SIGNATURE[0])
+  s="(bstring)";
+ else
+  s="(string)";
+ printf("\n%s <%s:%d,%d> (%d instruction%s, %d bytes at %p)\n",
+ 	(f->linedefined==0)?"main":"function",s,
+	f->linedefined,f->lastlinedefined,
+	S(f->sizecode),f->sizecode*Sizeof(Instruction),VOID(f));
+ printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
+	f->numparams,f->is_vararg?"+":"",SS(f->numparams),
+	S(f->maxstacksize),S(f->nups));
+ printf("%d local%s, %d constant%s, %d function%s\n",
+	S(f->sizelocvars),S(f->sizek),S(f->sizep));
+}
+
+static void PrintConstants(const Proto* f)
+{
+ int i,n=f->sizek;
+ printf("constants (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++)
+ {
+  printf("\t%d\t",i+1);
+  PrintConstant(f,i);
+  printf("\n");
+ }
+}
+
+static void PrintLocals(const Proto* f)
+{
+ int i,n=f->sizelocvars;
+ printf("locals (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++)
+ {
+  printf("\t%d\t%s\t%d\t%d\n",
+  i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
+ }
+}
+
+static void PrintUpvalues(const Proto* f)
+{
+ int i,n=f->sizeupvalues;
+ printf("upvalues (%d) for %p:\n",n,VOID(f));
+ if (f->upvalues==NULL) return;
+ for (i=0; i<n; i++)
+ {
+  printf("\t%d\t%s\n",i,getstr(f->upvalues[i]));
+ }
+}
+
+void PrintFunction(const Proto* f, int full)
+{
+ int i,n=f->sizep;
+ PrintHeader(f);
+ PrintCode(f);
+ if (full)
+ {
+  PrintConstants(f);
+  PrintLocals(f);
+  PrintUpvalues(f);
+ }
+ for (i=0; i<n; i++) PrintFunction(f->p[i],full);
+}

=== modified file 'normal/main.c'
--- normal/main.c	2008-07-29 14:07:47 +0000
+++ normal/main.c	2008-08-03 04:00:22 +0000
@@ -28,6 +28,7 @@
 #include <grub/env.h>
 #include <grub/parser.h>
 #include <grub/script.h>
+#include <grub/menu_viewer.h>
 
 grub_jmp_buf grub_exit_env;
 
@@ -147,14 +148,132 @@
   grub_env_unset_data_slot ("menu");
 }
 
+static void
+free_menu_entry_classes (struct grub_menu_entry_class *head)
+{
+  /* Free all the classes.  */
+  while (head)
+    {
+      struct grub_menu_entry_class *next;
+
+      grub_free (head->name);
+      next = head->next;
+      grub_free (head);
+      head = next;
+    }
+}
+
+/* The tag that can be added to a menu entry's title to specify a class
+   for the UI to use in selecting an icon or other visual attributes.  */
+static const char entry_class_attr_tag[] = "|class=";
+
+#define ENTRY_ATTR_SEPARATOR_CHAR ','
+
+/* Parse and strip a possible "class" attribute in the title.
+   This code is not designed to support other attributes than "class"
+   in the title since, we are planning to use a better method of
+   specifying this information in the future.  The parameter TITLE is
+   modified by storing a '\0' at the appropriate location to strip the
+   class information, if it exists.  The class list is stored into *HEAD.  */
+static struct grub_menu_entry_class *
+get_classes_from_entry_title (char *title)
+{
+  struct grub_menu_entry_class *head;
+  char *attr_start;
+
+  head = grub_malloc (sizeof (struct grub_menu_entry_class));
+  if (! head)
+    return 0;
+  head->name = 0;
+  head->next = 0;
+
+  attr_start = grub_strstr (title, entry_class_attr_tag);
+  if (attr_start)
+    {
+      struct grub_menu_entry_class *tail;
+      const char *p;
+
+      /* Trim the properties off of the title.  */
+      *attr_start = '\0';
+
+      /* Move the pointer to the beginning of the first class name.  */
+      attr_start += grub_strlen (entry_class_attr_tag);
+
+      tail = head;
+      p = attr_start;
+      while (p && *p)
+        {
+          const char *q;
+          const char *end;
+          const char *next_start;
+
+          /* Skip any leading whitespace.  */
+          while (*p && grub_isspace (*p))
+            p++;
+
+          /* Find the comma terminating this one ...  */
+          q = grub_strchr (p, ENTRY_ATTR_SEPARATOR_CHAR);
+          /* ... or if it's the last one, find the '\0' terminator.  */
+          if (q)
+            {
+              end = q - 1;
+              next_start = q + 1;
+            }
+          else
+            {
+              /* For the last class, extend it to the end.  */
+              end = p + grub_strlen (p);
+              next_start = 0;
+            }
+
+          /* Trim any trailing whitespace.  */
+          while (end > p && grub_isspace (*end))
+            end--;
+
+          grub_size_t len = end - p + 1;
+          /* Copy the class name into a new string.  */
+          char *class_name = grub_malloc (len + 1);
+          if (! class_name)
+            {
+              free_menu_entry_classes (head);
+              return 0;
+            }
+          grub_memcpy (class_name, p, len);
+          class_name[len] = '\0';
+
+          /* Create a new class and add it at the tail of the list.  */
+          struct grub_menu_entry_class *new_class;
+          new_class = grub_malloc (sizeof (struct grub_menu_entry_class));
+          if (! new_class)
+            {
+              grub_free (class_name);
+              free_menu_entry_classes (head);
+              return 0;
+            }
+          /* Fill in the new class node.  */
+          new_class->name = class_name;
+          new_class->next = 0;
+          /* Link the tail to it, and make it the new tail.  */
+          tail->next = new_class;
+          tail = new_class;
+
+          /* Advance the character pointer.  */
+          p = next_start;
+        }
+    }
+
+  return head;
+}
+
 grub_err_t
 grub_normal_menu_addentry (const char *title, struct grub_script *script,
 			   const char *sourcecode)
 {
-  const char *menutitle;
+  char *menutitle;
   const char *menusourcecode;
   grub_menu_t menu;
   grub_menu_entry_t *last;
+  struct grub_menu_entry_class *classes;
 
   menu = grub_env_get_data_slot("menu");
   if (! menu)
@@ -173,6 +292,14 @@
       return grub_errno;
     }
 
+  classes = get_classes_from_entry_title (menutitle);
+  if (! classes)
+    {
+      grub_free ((void *) menutitle);
+      grub_free ((void *) menusourcecode);
+      return grub_errno;
+    }
+
   /* Add the menu entry at the end of the list.  */
   while (*last)
     last = &(*last)->next;
@@ -180,6 +307,7 @@
   *last = grub_malloc (sizeof (**last));
   if (! *last)
     {
+      free_menu_entry_classes (classes);
       grub_free ((void *) menutitle);
       grub_free ((void *) menusourcecode);
       return grub_errno;
@@ -187,6 +315,7 @@
 
   (*last)->commands = script;
   (*last)->title = menutitle;
+  (*last)->classes = classes;
   (*last)->next = 0;
   (*last)->sourcecode = menusourcecode;
 
@@ -476,7 +605,7 @@
 
   if (menu && menu->size)
     {
-      grub_menu_run (menu, nested);
+      grub_menu_viewer_show_menu (menu, nested);
       if (nested)
 	free_menu (menu);
     }
@@ -519,6 +648,8 @@
   if (mod)
     grub_dl_ref (mod);
 
+  grub_menu_viewer_register (&grub_normal_terminal_menu_viewer);
+
   grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
 
   /* Register a command "normal" for the rescue mode.  */
@@ -535,6 +666,8 @@
 
   /* This registers some built-in commands.  */
   grub_command_init ();
+
+  grub_menu_viewer_init ();
 }
 
 GRUB_MOD_FINI(normal)

=== modified file 'normal/menu.c'
--- normal/menu.c	2008-02-09 11:00:19 +0000
+++ normal/menu.c	2008-07-26 23:37:04 +0000
@@ -21,9 +21,11 @@
 #include <grub/misc.h>
 #include <grub/loader.h>
 #include <grub/mm.h>
+#include <grub/time.h>
 #include <grub/machine/time.h>
 #include <grub/env.h>
 #include <grub/script.h>
+#include <grub/menu_viewer.h>
 
 static grub_uint8_t grub_color_menu_normal;
 static grub_uint8_t grub_color_menu_highlight;
@@ -241,8 +243,8 @@
 
 /* Return the current timeout. If the variable "timeout" is not set or
    invalid, return -1.  */
-static int
-get_timeout (void)
+int
+grub_menu_get_timeout (void)
 {
   char *val;
   int timeout;
@@ -269,8 +271,8 @@
 }
 
 /* Set current timeout in the variable "timeout".  */
-static void
-set_timeout (int timeout)
+void
+grub_menu_set_timeout (int timeout)
 {
   /* Ignore TIMEOUT if it is zero, because it will be unset really soon.  */
   if (timeout > 0)
@@ -308,6 +310,57 @@
   return entry;
 }
 
+/* Get the default menu entry index.  */
+int
+grub_menu_get_default_entry_index (grub_menu_t menu)
+{
+  int i = get_entry_number ("default");
+
+  /* If DEFAULT_ENTRY is not within the menu entries, fall back to
+     the first entry.  */
+  if (i < 0 || i >= menu->size)
+    i = 0;
+
+  return i;
+}
+
+/* Get the first entry number from the variable NAME, which is a 
+   space-separated list of nonnegative integers.  The entry number which
+   is returned is stripped from the value of NAME.  */
+static int
+get_and_remove_first_entry_number (const char *name)
+{
+  char *val;
+  char *tail;
+  int entry;
+  
+  val = grub_env_get (name);
+  if (! val)
+    return -1;
+  
+  grub_error_push ();
+  
+  entry = (int) grub_strtoul (val, &tail, 0);
+
+  if (grub_errno == GRUB_ERR_NONE)
+    {
+      /* Skip whitespace to find the next digit.  */
+      while (*tail && grub_isspace (*tail))
+	tail++;
+      grub_env_set (name, tail);
+    }
+  else
+    {
+      grub_env_unset (name);
+      grub_errno = GRUB_ERR_NONE;
+      entry = -1;
+    }
+
+  grub_error_pop ();
+  
+  return entry;
+}
+
 static void
 print_timeout (int timeout, int offset, int second_stage)
 {
@@ -332,15 +385,10 @@
   
   first = 0;
   
-  default_entry = get_entry_number ("default");
-
-  /* If DEFAULT_ENTRY is not within the menu entries, fall back to
-     the first entry.  */
-  if (default_entry < 0 || default_entry >= menu->size)
-    default_entry = 0;
+  default_entry = grub_menu_get_default_entry_index (menu);
 
   /* If timeout is 0, drawing is pointless (and ugly).  */
-  if (get_timeout () == 0)
+  if (grub_menu_get_timeout () == 0)
     return default_entry;
 
   offset = default_entry;
@@ -359,15 +407,15 @@
   print_entries (menu, first, offset);
   grub_refresh ();
 
-  timeout = get_timeout ();
+  timeout = grub_menu_get_timeout ();
 
   if (timeout > 0)
     print_timeout (timeout, offset, 0);
 
-  while (1)
+  while (!grub_menu_viewer_should_return ())
     {
       int c;
-      timeout = get_timeout ();
+      timeout = grub_menu_get_timeout ();
       
       if (timeout > 0)
 	{
@@ -377,7 +425,7 @@
 	  if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
 	    {
 	      timeout--;
-	      set_timeout (timeout);
+	      grub_menu_set_timeout (timeout);
 	      saved_time = current_time;
 	      print_timeout (timeout, offset, 1);
 	    }
@@ -468,6 +516,10 @@
 		}
 	      goto refresh;
 	      
+	    case 't':
+	      grub_env_set ("menuviewer", "protomenu");
+	      goto refresh;
+
 	    default:
 	      break;
 	    }
@@ -476,13 +528,14 @@
 	}
     }
 
-  /* Never reach here.  */
+  /* Exit menu without activating an item.  This occurs if the user presses
+   * 't', switching to the graphical menu viewer.  */
   return -1;
 }
 
 /* Run a menu entry.  */
-static void
-run_menu_entry (grub_menu_entry_t entry)
+void
+grub_menu_execute_entry(grub_menu_entry_t entry)
 {
   grub_script_execute (entry->commands);
   
@@ -491,15 +544,80 @@
     grub_command_execute ("boot", 0);
 }
 
+/* Execute ENTRY from the menu MENU, falling back to entries specified
+   in the environment variable "fallback" if it fails.  CALLBACK is a 
+   pointer to a struct of function pointers which are used to allow the
+   caller provide feedback to the user.  */
 void
-grub_menu_run (grub_menu_t menu, int nested)
+grub_menu_execute_with_fallback (grub_menu_t menu,
+				 grub_menu_entry_t entry,
+				 grub_menu_execute_callback_t callback,
+				 void *callback_data)
+{
+  int fallback_entry;
+
+  callback->notify_booting (callback_data, entry);
+
+  grub_menu_execute_entry (entry);
+
+  /* Deal with fallback entries.  */
+  while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
+	 >= 0)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+
+      entry = get_entry (menu, fallback_entry);
+      callback->notify_fallback (callback_data, entry);
+      grub_menu_execute_entry (entry);
+    }
+
+  if (grub_errno != GRUB_ERR_NONE)
+    callback->notify_failure (callback_data);
+}
+
+static void
+notify_booting (void *userdata __attribute__((unused)),
+		grub_menu_entry_t entry)
+{
+  grub_printf ("  Booting \'%s\'\n\n", entry->title);
+}
+
+static void
+notify_fallback (void *userdata __attribute__((unused)),
+		 grub_menu_entry_t entry)
+{
+  grub_printf ("\n  Falling back to \'%s\'\n\n", entry->title);
+  grub_millisleep (2000);
+}
+
+static void
+notify_execution_failure (void *userdata __attribute__((unused)))
+{
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_print_error ();
+      grub_errno = GRUB_ERR_NONE;
+
+      grub_wait_after_message ();
+    }
+}
+
+static struct grub_menu_execute_callback execution_callback = 
+{
+  .notify_booting = notify_booting,
+  .notify_fallback = notify_fallback,
+  .notify_failure = notify_execution_failure
+};
+
+static grub_err_t
+show_menu (grub_menu_t menu, int nested)
 {
   while (1)
     {
       int boot_entry;
       grub_menu_entry_t e;
-      int fallback_entry;
-      
+
       boot_entry = run_menu (menu, nested);
       if (boot_entry < 0)
 	break;
@@ -507,34 +625,18 @@
       e = get_entry (menu, boot_entry);
       if (! e)
 	continue; /* Menu is empty.  */
-	
+
       grub_cls ();
       grub_setcursor (1);
 
-      grub_printf ("  Booting \'%s\'\n\n", e->title);
-  
-      run_menu_entry (e);
-
-      /* Deal with a fallback entry.  */
-      /* FIXME: Multiple fallback entries like GRUB Legacy.  */
-      fallback_entry = get_entry_number ("fallback");
-      if (fallback_entry >= 0)
-	{
-	  grub_print_error ();
-	  grub_errno = GRUB_ERR_NONE;
-	  
-	  e = get_entry (menu, fallback_entry);
-	  grub_env_unset ("fallback");
-	  grub_printf ("\n  Falling back to \'%s\'\n\n", e->title);
-	  run_menu_entry (e);
-	}
-
-      if (grub_errno != GRUB_ERR_NONE)
-	{
-	  grub_print_error ();
-	  grub_errno = GRUB_ERR_NONE;
-
-	  grub_wait_after_message ();
-	}
+      grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
     }
+
+  return GRUB_ERR_NONE;
 }
+
+struct grub_menu_viewer grub_normal_terminal_menu_viewer =
+{
+  .name = "terminal",
+  .show_menu = show_menu
+};

=== modified file 'term/gfxterm.c'
--- term/gfxterm.c	2008-01-01 12:02:07 +0000
+++ term/gfxterm.c	2008-07-19 19:56:06 +0000
@@ -28,14 +28,12 @@
 #include <grub/mm.h>
 #include <grub/env.h>
 #include <grub/video.h>
+#include <grub/gfxterm.h>
 #include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
 
 #define DEFAULT_VIDEO_WIDTH	640
 #define DEFAULT_VIDEO_HEIGHT	480
-#define DEFAULT_VIDEO_FLAGS	0
-
-#define DEFAULT_CHAR_WIDTH  	8
-#define DEFAULT_CHAR_HEIGHT 	16
 
 #define DEFAULT_BORDER_WIDTH	10
 
@@ -91,6 +89,9 @@
   unsigned int cursor_y;
   int cursor_state;
 
+  /* Font settings. */
+  grub_font_t font;
+
   /* Terminal color settings.  */
   grub_uint8_t standard_color_setting;
   grub_uint8_t normal_color_setting;
@@ -107,10 +108,20 @@
   struct grub_colored_char *text_buffer;
 };
 
+static int refcount;
+static struct grub_video_render_target *render_target;
+static grub_video_rect_t window;
 static struct grub_virtual_screen virtual_screen;
+static grub_gfxterm_repaint_callback_t repaint_callback;
+
+static grub_err_t init_window (struct grub_video_render_target *target,
+                               int x, int y, int width, int height, 
+                               const char *font_name, int border_width);
+
+static void destroy_window (void);
+
 
 static grub_dl_t my_mod;
-static struct grub_video_mode_info mode_info;
 
 static struct grub_video_render_target *text_layer;
 
@@ -170,18 +181,25 @@
 
 static grub_err_t
 grub_virtual_screen_setup (unsigned int x, unsigned int y,
-                           unsigned int width, unsigned int height)
+                           unsigned int width, unsigned int height,
+                           const char *font_name)
 {
   /* Free old virtual screen.  */
   grub_virtual_screen_free ();
 
   /* Initialize with default data.  */
+  virtual_screen.font = grub_font_get (font_name);
+  if (!virtual_screen.font)
+    return grub_error (GRUB_ERR_BAD_FONT,
+                       "No font loaded.");
   virtual_screen.width = width;
   virtual_screen.height = height;
   virtual_screen.offset_x = x;
   virtual_screen.offset_y = y;
-  virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
-  virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
+  virtual_screen.char_width = 
+    grub_font_get_max_char_width (virtual_screen.font);
+  virtual_screen.char_height = 
+    grub_font_get_max_char_height (virtual_screen.font);
   virtual_screen.cursor_x = 0;
   virtual_screen.cursor_y = 0;
   virtual_screen.cursor_state = 1;
@@ -227,281 +245,129 @@
 }
 
 static grub_err_t
+init_window (struct grub_video_render_target *target,
+             int x, int y, int width, int height, 
+             const char *font_name, int border_width)
+{
+  /* Clean up any prior instance.  */
+  destroy_window ();
+
+  /* Create virtual screen.  */
+  if (grub_virtual_screen_setup (border_width, border_width, 
+                                 width - 2 * border_width, 
+                                 height - 2 * border_width, 
+                                 font_name) 
+      != GRUB_ERR_NONE)
+    {
+      return grub_errno;
+    }
+
+  /* Set the render target.  */
+  render_target = target;
+
+  /* Set window bounds.  */
+  window.x = x;
+  window.y = y;
+  window.width = width;
+  window.height = height;
+
+  /* Mark whole window as dirty.  */
+  dirty_region_reset ();
+  dirty_region_add (0, 0, width, height);
+
+  return (grub_errno = GRUB_ERR_NONE);
+}
+
+grub_err_t
+grub_gfxterm_init_window (struct grub_video_render_target *target,
+                          int x, int y, int width, int height, 
+                          const char *font_name, int border_width)
+{
+  grub_errno = GRUB_ERR_NONE;
+  if (refcount++ == 0)
+    init_window (target, x, y, width, height, font_name, border_width);
+  return grub_errno;
+}
+
+static grub_err_t
 grub_gfxterm_init (void)
 {
-  char *modevar;
-  int width = DEFAULT_VIDEO_WIDTH;
-  int height = DEFAULT_VIDEO_HEIGHT;
-  int depth = -1;
-  int flags = DEFAULT_VIDEO_FLAGS;
-  grub_video_color_t color;
+  /* If gfxterm has already been initialized by calling the init_window
+     function, then leave it alone when it is set as the current terminal. */
+  if (refcount++ != 0)
+    return GRUB_ERR_NONE;
 
   /* Parse gfxmode environment variable if set.  */
-  modevar = grub_env_get ("gfxmode");
-  if (modevar)
-    {
-      char *tmp;
-      char *next_mode;
-      char *current_mode;
-      char *param;
-      char *value;
-      int mode_found = 0;
-
-      /* Take copy of env.var. as we don't want to modify that.  */
-      tmp = grub_strdup (modevar);
-      modevar = tmp;
-
-      if (grub_errno != GRUB_ERR_NONE)
-        return grub_errno;
-        
-      /* Initialize next mode.  */
-      next_mode = modevar;
-      
-      /* Loop until all modes has been tested out.  */
-      while (next_mode != NULL)
-        {
-          /* Use last next_mode as current mode.  */
-          tmp = next_mode;
-          
-          /* Reset video mode settings.  */
-          width = DEFAULT_VIDEO_WIDTH;
-          height = DEFAULT_VIDEO_HEIGHT;
-          depth = -1;
-          flags = DEFAULT_VIDEO_FLAGS;
-        
-          /* Save position of next mode and separate modes.  */
-          next_mode = grub_strchr(next_mode, ';');
-          if (next_mode)
-            {
-              *next_mode = 0;
-              next_mode++;
-            }
-
-          /* Skip whitespace.  */
-          while (grub_isspace (*tmp))
-            tmp++;
-
-          /* Initialize token holders.  */
-          current_mode = tmp;
-          param = tmp;
-          value = NULL;
-
-          /* Parse <width>x<height>[x<depth>]*/
-
-          /* Find width value.  */
-          value = param;
-          param = grub_strchr(param, 'x');
-          if (param == NULL)
-            {
-              grub_err_t rc;
-              
-              /* First setup error message.  */
-              rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
-                               "Invalid mode: %s\n",
-                               current_mode);
-              
-              /* Free memory before returning.  */
-              grub_free (modevar);
-              
-              return rc;
-            }
-
-          *param = 0;
-          param++;
-
-          width = grub_strtoul (value, 0, 0);
-          if (grub_errno != GRUB_ERR_NONE)
-            {
-              grub_err_t rc;
-              
-              /* First setup error message.  */
-              rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
-                               "Invalid mode: %s\n",
-                               current_mode);
-              
-              /* Free memory before returning.  */
-              grub_free (modevar);
-              
-              return rc;
-            }
-
-          /* Find height value.  */
-          value = param;
-          param = grub_strchr(param, 'x');
-          if (param == NULL)
-            {
-              height = grub_strtoul (value, 0, 0);
-              if (grub_errno != GRUB_ERR_NONE)
-                {
-                  grub_err_t rc;
-                  
-                  /* First setup error message.  */
-                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
-                                   "Invalid mode: %s\n",
-                                   current_mode);
-                                   
-                  /* Free memory before returning.  */
-                  grub_free (modevar);
-                  
-                  return rc;
-                }
-            }
-          else
-            {
-              /* We have optional color depth value.  */
-              *param = 0;
-              param++;
-
-              height = grub_strtoul (value, 0, 0);
-              if (grub_errno != GRUB_ERR_NONE)
-                {
-                  grub_err_t rc;
-                  
-                  /* First setup error message.  */
-                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
-                                   "Invalid mode: %s\n",
-                                   current_mode);
-                                   
-                  /* Free memory before returning.  */
-                  grub_free (modevar);
-                  
-                  return rc;
-                }
-
-              /* Convert color depth value.  */
-              value = param;
-              depth = grub_strtoul (value, 0, 0);
-              if (grub_errno != GRUB_ERR_NONE)
-                {
-                  grub_err_t rc;
-                  
-                  /* First setup error message.  */
-                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
-                                   "Invalid mode: %s\n",
-                                   current_mode);
-                                   
-                  /* Free memory before returning.  */
-                  grub_free (modevar);
-                  
-                  return rc;
-                }
-            }
-          
-          /* Try out video mode.  */
-          
-          /* If we have 8 or less bits, then assume that it is indexed color mode.  */
-          if ((depth <= 8) && (depth != -1))
-            flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
-
-          /* We have more than 8 bits, then assume that it is RGB color mode.  */
-          if (depth > 8)
-            flags |= GRUB_VIDEO_MODE_TYPE_RGB;
-
-          /* If user requested specific depth, forward that information to driver.  */
-          if (depth != -1)
-            flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
-                     & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
-
-          /* Try to initialize requested mode.  Ignore any errors.  */
-          grub_error_push ();
-          if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
-            {
-              grub_error_pop ();
-              continue;
-            }
-            
-          /* Figure out what mode we ended up.  */
-          if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
-            {
-              /* Couldn't get video mode info, restore old mode and continue to next one.  */
-              grub_error_pop ();
-              
-              grub_video_restore ();
-              continue;
-            }
-          
-          /* Restore state of error stack.  */
-          grub_error_pop ();
-          
-          /* Mode found!  Exit loop.  */
-          mode_found = 1;
-          break;
-        }
-
-      /* Free memory.  */
-      grub_free (modevar);
-      
-      if (!mode_found)
-        return grub_error (GRUB_ERR_BAD_ARGUMENT,
-                           "No suitable mode found.");
-    }
-  else
-    {
-      /* No gfxmode variable set, use defaults.  */
-      
-      /* If we have 8 or less bits, then assume that it is indexed color mode.  */
-      if ((depth <= 8) && (depth != -1))
-        flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
-
-      /* We have more than 8 bits, then assume that it is RGB color mode.  */
-      if (depth > 8)
-        flags |= GRUB_VIDEO_MODE_TYPE_RGB;
-
-      /* If user requested specific depth, forward that information to driver.  */
-      if (depth != -1)
-        flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
-                 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
-
-      /* Initialize user requested mode.  */
-      if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
-        return grub_errno;
-
-      /* Figure out what mode we ended up.  */
-      if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
-        {
-          grub_video_restore ();
-          return grub_errno;
-        }
+  const char *modevar = grub_env_get ("gfxmode");
+  if (grub_video_setup_preferred_mode (modevar, 0, 
+                                       DEFAULT_VIDEO_WIDTH, 
+                                       DEFAULT_VIDEO_HEIGHT) 
+      != GRUB_ERR_NONE)
+    return grub_errno;
+
+  /* Figure out what mode we ended up.  */
+  struct grub_video_mode_info mode_info;
+  if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+    {
+      grub_video_restore ();
+      return grub_errno;
     }
 
   /* Make sure screen is black.  */
-  color = grub_video_map_rgb (0, 0, 0);
-  grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
+  grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), 
+                        0, 0, mode_info.width, mode_info.height);
   bitmap = 0;
 
+  /* Select the font to use.  */
+  char *font_name = grub_env_get ("gfxterm_font");
+  if (!font_name)
+    font_name = "";   /* Allow fallback to any font.  */
+
   /* Leave borders for virtual screen.  */
-  width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
-  height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
-
-  /* Create virtual screen.  */
-  if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
-                                 width, height) != GRUB_ERR_NONE)
+  if (init_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY,
+                   0, 0, mode_info.width, mode_info.height,
+                   font_name, 
+                   DEFAULT_BORDER_WIDTH) != GRUB_ERR_NONE)
     {
       grub_video_restore ();
       return grub_errno;
     }
 
-  /* Mark whole screen as dirty.  */
-  dirty_region_reset ();
-  dirty_region_add (0, 0, mode_info.width, mode_info.height);
-
   return (grub_errno = GRUB_ERR_NONE);
 }
 
+static void
+destroy_window (void)
+{
+  if (bitmap)
+    {
+      grub_video_bitmap_destroy (bitmap);
+      bitmap = 0;
+    }
+
+  repaint_callback = 0;
+  grub_virtual_screen_free ();
+}
+
+void
+grub_gfxterm_destroy_window (void)
+{
+  if (--refcount == 0)
+    destroy_window ();
+}
+
 static grub_err_t
 grub_gfxterm_fini (void)
 {
-  if (bitmap)
+  /* Don't destroy an explicitly initialized terminal instance when it is
+     unset as the current terminal.  */
+  if (--refcount == 0)
     {
-      grub_video_bitmap_destroy (bitmap);
-      bitmap = 0;
+      destroy_window ();
+      grub_video_restore ();
     }
 
-  grub_virtual_screen_free ();
-
-  grub_video_restore ();
-
-  return GRUB_ERR_NONE;
+  return (grub_errno = GRUB_ERR_NONE);
 }
 
 static void
@@ -509,9 +375,15 @@
                     unsigned int width, unsigned int height)
 {
   grub_video_color_t color;
-
-  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
-
+  grub_video_rect_t saved_view;
+
+  grub_video_set_active_render_target (render_target);
+  /* Save viewport and set it to our window. */
+  grub_video_get_viewport ((unsigned *) &saved_view.x, 
+                           (unsigned *) &saved_view.y, 
+                           (unsigned *) &saved_view.width, 
+                           (unsigned *) &saved_view.height);
+  grub_video_set_viewport (window.x, window.y, window.width, window.height);
 
   if (bitmap)
     {
@@ -578,6 +450,14 @@
                                      y - virtual_screen.offset_y,
                                      width, height);      
     }
+
+  /* Restore saved viewport. */
+  grub_video_set_viewport (saved_view.x, saved_view.y,
+                           saved_view.width, saved_view.height);
+  grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+  
+  if (repaint_callback)
+    repaint_callback (x, y, width, height);
 }
 
 static void
@@ -661,11 +541,12 @@
 write_char (void)
 {
   struct grub_colored_char *p;
-  struct grub_font_glyph glyph;
+  struct grub_font_glyph *glyph;
   grub_video_color_t color;
   grub_video_color_t bgcolor;
   unsigned int x;
   unsigned int y;
+  int ascent;
 
   /* Find out active character.  */
   p = (virtual_screen.text_buffer
@@ -675,7 +556,8 @@
   p -= p->index;
 
   /* Get glyph for character.  */
-  grub_font_get_glyph (p->code, &glyph);
+  glyph = grub_font_get_glyph (virtual_screen.font, p->code);
+  ascent = grub_font_get_ascent (virtual_screen.font);
 
   color = p->fg_color;
   bgcolor = p->bg_color;
@@ -685,13 +567,13 @@
 
   /* Render glyph to text layer.  */
   grub_video_set_active_render_target (text_layer);
-  grub_video_fill_rect (bgcolor, x, y, glyph.width, glyph.height);
-  grub_video_blit_glyph (&glyph, color, x, y);
+  grub_video_fill_rect (bgcolor, x, y, glyph->width, glyph->height);
+  grub_video_blit_glyph (glyph, color, x, y + ascent);
   grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
 
   /* Mark character to be drawn.  */
   dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
-                    glyph.width, glyph.height);
+                    glyph->width, glyph->height);
 }
 
 static void
@@ -705,7 +587,8 @@
 
   /* Determine cursor properties and position on text layer. */
   x = virtual_screen.cursor_x * virtual_screen.char_width;
-  y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;  
+  y = (virtual_screen.cursor_y * virtual_screen.char_height   
+       + grub_font_get_ascent (virtual_screen.font));
   width = virtual_screen.char_width;
   height = 2;
 
@@ -769,7 +652,16 @@
       dirty_region_add_virtualscreen ();
     }
   else
-    {      
+    {
+      grub_video_rect_t saved_view;
+      grub_video_set_active_render_target (render_target);
+      /* Save viewport and set it to our window.  */
+      grub_video_get_viewport ((unsigned *) &saved_view.x, 
+                               (unsigned *) &saved_view.y, 
+                               (unsigned *) &saved_view.width, 
+                               (unsigned *) &saved_view.height);
+      grub_video_set_viewport (window.x, window.y, window.width, window.height);
+
       /* Clear new border area.  */
       grub_video_fill_rect (color, 
                             virtual_screen.offset_x, virtual_screen.offset_y, 
@@ -778,10 +670,18 @@
       /* Scroll physical screen.  */
       grub_video_scroll (color, 0, -virtual_screen.char_height);      
 
+      /* Restore saved viewport. */
+      grub_video_set_viewport (saved_view.x, saved_view.y,
+                               saved_view.width, saved_view.height);
+      grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
+
       /* Draw cursor if visible.  */
       if (virtual_screen.cursor_state)
         write_cursor ();
     }
+
+  if (repaint_callback)
+    repaint_callback (window.x, window.y, window.width, window.height);
 }
 
 static void
@@ -822,14 +722,18 @@
     }
   else
     {
-      struct grub_font_glyph glyph;
+      struct grub_font_glyph *glyph;
       struct grub_colored_char *p;
+      unsigned char_width;
 
       /* Get properties of the character.  */    
-      grub_font_get_glyph (c, &glyph);
+      glyph = grub_font_get_glyph (virtual_screen.font, c);
+
+      /* TODO [CDB] Fix wide characters.  Bi-width font? */
+      char_width = 1;
 
       /* If we are about to exceed line length, wrap to next line.  */
-      if (virtual_screen.cursor_x + glyph.char_width > virtual_screen.columns)
+      if (virtual_screen.cursor_x + char_width > virtual_screen.columns)
         grub_putchar ('\n');
 
       /* Find position on virtual screen, and fill information.  */
@@ -839,18 +743,18 @@
       p->code = c;
       p->fg_color = virtual_screen.fg_color;
       p->bg_color = virtual_screen.bg_color;
-      p->width = glyph.char_width - 1;
+      p->width = char_width - 1;
       p->index = 0;
 
       /* If we have large glyph, add fixup info.  */
-      if (glyph.char_width > 1)
+      if (char_width > 1)
         {
           unsigned i;
 
-          for (i = 1; i < glyph.char_width; i++)
+          for (i = 1; i < char_width; i++)
             {
               p[i].code = ' ';
-              p[i].width = glyph.char_width - 1;
+              p[i].width = char_width - 1;
               p[i].index = i;
             }
         }
@@ -859,7 +763,7 @@
       write_char ();
 
       /* Make sure we scroll screen when needed and wrap line correctly.  */
-      virtual_screen.cursor_x += glyph.char_width;
+      virtual_screen.cursor_x += char_width;
       if (virtual_screen.cursor_x >= virtual_screen.columns)
         {
           virtual_screen.cursor_x = 0;
@@ -877,13 +781,17 @@
 }
 
 static grub_ssize_t
-grub_gfxterm_getcharwidth (grub_uint32_t c)
+grub_gfxterm_getcharwidth (grub_uint32_t c __attribute__((unused)))
 {
-  struct grub_font_glyph glyph;
-
-  grub_font_get_glyph (c, &glyph);
-
-  return glyph.char_width;
+#if 0
+  struct grub_font_glyph *glyph;
+
+  glyph = grub_font_get_glyph (c);
+
+  return glyph->char_width;
+#else
+  return 1;   /* TODO [CDB] Fix wide characters. */
+#endif
 }
 
 static grub_uint16_t
@@ -945,7 +853,8 @@
   /* Clear text layer.  */
   grub_video_set_active_render_target (text_layer);
   color = virtual_screen.bg_color;
-  grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
+  grub_video_fill_rect (color, 0, 0,
+                        virtual_screen.width, virtual_screen.height);
   grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
 
   /* Mark virtual screen to be redrawn.  */
@@ -1014,8 +923,23 @@
   dirty_region_redraw ();
 }
 
+void 
+grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func)
+{
+  repaint_callback = func;
+}
+
+/* Option array indices. */
+#define BACKGROUND_CMD_ARGINDEX_MODE 0
+
+static const struct grub_arg_option background_image_cmd_options[] = {
+  {"mode", 'm', 0, "Background image mode (`stretch', `normal').", 0, 
+    ARG_TYPE_STRING},
+  {0, 0, 0, 0, 0, 0}
+};
+
 static grub_err_t
-grub_gfxterm_background_image_cmd (struct grub_arg_list *state __attribute__ ((unused)),
+grub_gfxterm_background_image_cmd (struct grub_arg_list *state,
                                    int argc,
                                    char **args)
 {
@@ -1031,7 +955,7 @@
       
       /* Mark whole screen as dirty.  */
       dirty_region_reset ();
-      dirty_region_add (0, 0, mode_info.width, mode_info.height);
+      dirty_region_add (0, 0, window.width, window.height);
     }
 
   /* If filename was provided, try to load that.  */
@@ -1042,16 +966,40 @@
     if (grub_errno != GRUB_ERR_NONE)
       return grub_errno;
 
+    /* Determine if the bitmap should be scaled to fit the screen. */
+    if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set
+        || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg,
+                        "stretch") == 0)
+        {
+          if (window.width != (int) grub_video_bitmap_get_width (bitmap)
+              || window.height != (int) grub_video_bitmap_get_height (bitmap)) 
+            {
+              struct grub_video_bitmap *scaled_bitmap;
+              grub_video_bitmap_create_scaled (&scaled_bitmap,
+                                              window.width, 
+                                              window.height,
+                                              bitmap,
+                                              GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
+              if (grub_errno == GRUB_ERR_NONE)
+                {
+                  /* Replace the original bitmap with the scaled one. */
+                  grub_video_bitmap_destroy (bitmap);
+                  bitmap = scaled_bitmap;
+                }
+            }
+        }
+
+
     /* If bitmap was loaded correctly, display it.  */
     if (bitmap)
       {
         /* Determine bitmap dimensions.  */
         bitmap_width = grub_video_bitmap_get_width (bitmap);
-        bitmap_height = grub_video_bitmap_get_width (bitmap);
+        bitmap_height = grub_video_bitmap_get_height (bitmap);
         
         /* Mark whole screen as dirty.  */
         dirty_region_reset ();
-        dirty_region_add (0, 0, mode_info.width, mode_info.height);
+        dirty_region_add (0, 0, window.width, window.height);
       }
     }
   
@@ -1082,9 +1030,16 @@
     .next = 0
   };
 
+grub_term_t
+grub_gfxterm_get_term (void)
+{
+  return &grub_video_term;
+}
+
 GRUB_MOD_INIT(term_gfxterm)
 {
   my_mod = mod;
+  refcount = 0;
   grub_term_register (&grub_video_term);
 
   grub_register_command ("background_image",
@@ -1092,7 +1047,7 @@
                          GRUB_COMMAND_FLAG_BOTH,
                          "background_image",
                          "Load background image for active terminal",
-                         0);
+                         background_image_cmd_options);
 }
 
 GRUB_MOD_FINI(term_gfxterm)

=== modified file 'term/i386/pc/vesafb.c'
--- term/i386/pc/vesafb.c	2007-12-30 08:52:06 +0000
+++ term/i386/pc/vesafb.c	2008-07-03 14:12:08 +0000
@@ -250,10 +250,11 @@
 	  break;
 
 	default:
-	  return grub_font_get_glyph (code, bitmap, width);
+	  return grub_font_get_glyph_any (code, bitmap, width);
 	}
     }
 
+  /* TODO [CDB] This is wrong for the new font module.  Should it be fixed? */
   if (bitmap)
     grub_memcpy (bitmap,
 		 vga_font + code * virtual_screen.char_height,

=== modified file 'term/i386/pc/vga.c'
--- term/i386/pc/vga.c	2008-01-21 15:48:27 +0000
+++ term/i386/pc/vga.c	2008-07-03 14:12:08 +0000
@@ -65,6 +65,7 @@
 static struct colored_char text_buf[TEXT_WIDTH * TEXT_HEIGHT];
 static unsigned char saved_map_mask;
 static int page = 0;
+static grub_font_t font = 0;
 
 #define SEQUENCER_ADDR_PORT	0x3C4
 #define SEQUENCER_DATA_PORT	0x3C5
@@ -161,6 +162,9 @@
   saved_map_mask = get_map_mask ();
   set_map_mask (0x0f);
   set_start_address (PAGE_OFFSET (page));
+  font = grub_font_get ("");  /* Choose any font, for now. */
+  if (!font)
+    return grub_error (GRUB_ERR_BAD_FONT, "No font loaded.");
   
   return GRUB_ERR_NONE;
 }
@@ -185,7 +189,7 @@
 write_char (void)
 {
   struct colored_char *p = text_buf + xpos + ypos * TEXT_WIDTH;
-  struct grub_font_glyph glyph;
+  struct grub_font_glyph *glyph;
   unsigned char *mem_base;
   unsigned plane;
 
@@ -194,7 +198,7 @@
   p -= p->index;
 
   /* Get glyph for character.  */
-  grub_font_get_glyph (p->code, &glyph);
+  glyph = grub_font_get_glyph (font, p->code);
   
   for (plane = 0x01; plane <= 0x08; plane <<= 1)
     {
@@ -210,17 +214,21 @@
 	{
 	  unsigned i;
 
-	  for (i = 0; i < glyph.char_width && offset < 32; i++)
+          unsigned char_width = 1; /* TODO [CDB] Figure out wide characters. */
+          /* TODO [CDB] Re-implement glyph drawing for vga module. */
+#if 0
+	  for (i = 0; i < char_width && offset < 32; i++)
 	    {
 	      unsigned char fg_mask, bg_mask;
 	      
-	      fg_mask = (p->fg_color & plane) ? glyph.bitmap[offset] : 0;
-	      bg_mask = (p->bg_color & plane) ? ~(glyph.bitmap[offset]) : 0;
+	      fg_mask = (p->fg_color & plane) ? glyph->bitmap[offset] : 0;
+	      bg_mask = (p->bg_color & plane) ? ~(glyph->bitmap[offset]) : 0;
 	      offset++;
 
 	      if (check_vga_mem (mem + i))
 		mem[i] = (fg_mask | bg_mask);
 	    }
+#endif /* 0 */ 
 	}
     }
 
@@ -320,36 +328,37 @@
     }
   else
     {
-      struct grub_font_glyph glyph;
+      struct grub_font_glyph *glyph;
       struct colored_char *p;
+      unsigned char_width = 1;
       
-      grub_font_get_glyph(c, &glyph);
+      glyph = grub_font_get_glyph(font, c);
 
-      if (xpos + glyph.char_width > TEXT_WIDTH)
+      if (xpos + char_width > TEXT_WIDTH)
 	grub_putchar ('\n');
 
       p = text_buf + xpos + ypos * TEXT_WIDTH;
       p->code = c;
       p->fg_color = fg_color;
       p->bg_color = bg_color;
-      p->width = glyph.char_width - 1;
+      p->width = char_width - 1;
       p->index = 0;
 
-      if (glyph.char_width > 1)
+      if (char_width > 1)
 	{
 	  unsigned i;
 
-	  for (i = 1; i < glyph.char_width; i++)
+	  for (i = 1; i < char_width; i++)
 	    {
 	      p[i].code = ' ';
-	      p[i].width = glyph.char_width - 1;
+	      p[i].width = char_width - 1;
 	      p[i].index = i;
 	    }
 	}
 	  
       write_char ();
   
-      xpos += glyph.char_width;
+      xpos += char_width;
       if (xpos >= TEXT_WIDTH)
 	{
 	  xpos = 0;
@@ -381,11 +390,16 @@
 static grub_ssize_t
 grub_vga_getcharwidth (grub_uint32_t c)
 {
+#if 0
   struct grub_font_glyph glyph;
   
-  grub_font_get_glyph (c, &glyph);
+  glyph = grub_font_get_glyph (c);
   
   return glyph.char_width;
+#else
+  /* TODO [CDB] Glyph wide characters? vga? */
+  return 1;
+#endif
 }
 
 static grub_uint16_t

=== added directory 'util/fonttool'
=== added file 'util/fonttool/build.xml'
--- util/fonttool/build.xml	1970-01-01 00:00:00 +0000
+++ util/fonttool/build.xml	2008-07-03 14:08:39 +0000
@@ -0,0 +1,23 @@
+<project name="fonttool" default="jar" basedir=".">
+    <description>GRUB 2 font tool.</description>
+
+    <target name="clean">
+        <delete dir="build"/>
+    </target>
+
+    <target name="compile">
+        <mkdir dir="build/src"/>
+        <javac srcdir="src" destdir="build/src" source="1.5" target="1.5"
+               optimize="yes" debug="yes" encoding="UTF-8"/>
+    </target>
+
+    <target name="jar" depends="compile">
+        <jar jarfile="build/fonttool.jar" compress="yes">
+            <fileset dir="build/src"/>
+            <fileset dir="src">
+                <include name="*.txt"/>
+                <include name="*.png"/>
+            </fileset>
+        </jar>
+    </target>
+</project>

=== added file 'util/fonttool/fonttool.iml'
--- util/fonttool/fonttool.iml	1970-01-01 00:00:00 +0000
+++ util/fonttool/fonttool.iml	2008-07-03 14:08:39 +0000
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+  <component name="ModuleRootManager" />
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$APPLICATION_HOME_DIR$/lib/junit-4.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntryProperties />
+  </component>
+</module>
+

=== added file 'util/fonttool/fonttool.ipr'
--- util/fonttool/fonttool.ipr	1970-01-01 00:00:00 +0000
+++ util/fonttool/fonttool.ipr	2008-07-03 14:08:39 +0000
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" relativePaths="false">
+  <component name="AntConfiguration">
+    <defaultAnt bundledAnt="true" />
+  </component>
+  <component name="BuildJarProjectSettings">
+    <option name="BUILD_JARS_ON_MAKE" value="false" />
+  </component>
+  <component name="CodeStyleProjectProfileManger">
+    <option name="PROJECT_PROFILE" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+  </component>
+  <component name="CodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS">
+      <value>
+        <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
+        <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
+        <option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" />
+        <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
+        <option name="ALIGN_MULTILINE_THROWS_LIST" value="true" />
+        <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
+        <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" />
+        <option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
+        <option name="IMPORT_LAYOUT_TABLE">
+          <value>
+            <package name="java" withSubpackages="true" />
+            <package name="javax" withSubpackages="true" />
+            <package name="" withSubpackages="true" />
+          </value>
+        </option>
+        <option name="RIGHT_MARGIN" value="80" />
+      </value>
+    </option>
+    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+  </component>
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <option name="DEPLOY_AFTER_MAKE" value="0" />
+    <resourceExtensions>
+      <entry name=".+\.(properties|xml|html|dtd|tld)" />
+      <entry name=".+\.(gif|png|jpeg|jpg)" />
+    </resourceExtensions>
+    <wildcardResourcePatterns>
+      <entry name="?*.properties" />
+      <entry name="?*.xml" />
+      <entry name="?*.gif" />
+      <entry name="?*.png" />
+      <entry name="?*.jpeg" />
+      <entry name="?*.jpg" />
+      <entry name="?*.html" />
+      <entry name="?*.dtd" />
+      <entry name="?*.tld" />
+      <entry name=".bzr" />
+    </wildcardResourcePatterns>
+  </component>
+  <component name="DataSourceManagerImpl" />
+  <component name="DependenciesAnalyzeManager">
+    <option name="myForwardDirection" value="false" />
+  </component>
+  <component name="DependencyValidationManager" />
+  <component name="EclipseCompilerSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="true" />
+    <option name="DEPRECATION" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="EclipseEmbeddedCompilerSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="true" />
+    <option name="DEPRECATION" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="EntryPointsManager">
+    <entry_points />
+  </component>
+  <component name="ExportToHTMLSettings">
+    <option name="PRINT_LINE_NUMBERS" value="false" />
+    <option name="OPEN_IN_BROWSER" value="false" />
+    <option name="OUTPUT_DIRECTORY" />
+  </component>
+  <component name="GUI Designer component loader factory" />
+  <component name="IdProvider" IDEtalkID="FEF368E009900571CCFB90CB4A0CEBC9" />
+  <component name="InspectionProjectProfileManager">
+    <option name="PROJECT_PROFILE" value="Project Default" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <scopes />
+    <profiles>
+      <profile version="1.0" is_locked="false">
+        <option name="myName" value="Project Default" />
+        <option name="myLocal" value="false" />
+        <used_levels>
+          <error>
+            <option name="myName" value="ERROR" />
+            <option name="myVal" value="400" />
+          </error>
+          <warning>
+            <option name="myName" value="WARNING" />
+            <option name="myVal" value="300" />
+          </warning>
+          <information>
+            <option name="myName" value="INFO" />
+            <option name="myVal" value="200" />
+          </information>
+          <server>
+            <option name="myName" value="SERVER PROBLEM" />
+            <option name="myVal" value="100" />
+          </server>
+        </used_levels>
+      </profile>
+    </profiles>
+  </component>
+  <component name="JavacSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="DEPRECATION" value="true" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="JavadocGenerationManager">
+    <option name="OUTPUT_DIRECTORY" />
+    <option name="OPTION_SCOPE" value="protected" />
+    <option name="OPTION_HIERARCHY" value="true" />
+    <option name="OPTION_NAVIGATOR" value="true" />
+    <option name="OPTION_INDEX" value="true" />
+    <option name="OPTION_SEPARATE_INDEX" value="true" />
+    <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+    <option name="OPTION_DEPRECATED_LIST" value="true" />
+    <option name="OTHER_OPTIONS" value="" />
+    <option name="HEAP_SIZE" />
+    <option name="LOCALE" />
+    <option name="OPEN_IN_BROWSER" value="true" />
+  </component>
+  <component name="JikesSettings">
+    <option name="JIKES_PATH" value="" />
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="DEPRECATION" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="IS_EMACS_ERRORS_MODE" value="true" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+  </component>
+  <component name="LogConsolePreferences">
+    <option name="FILTER_ERRORS" value="false" />
+    <option name="FILTER_WARNINGS" value="false" />
+    <option name="FILTER_INFO" value="true" />
+    <option name="CUSTOM_FILTER" />
+  </component>
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/fonttool.iml" filepath="$PROJECT_DIR$/fonttool.iml" />
+    </modules>
+  </component>
+  <component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectRunConfigurationManager" />
+  <component name="RmicSettings">
+    <option name="IS_EANABLED" value="false" />
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="GENERATE_IIOP_STUBS" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+  </component>
+  <component name="StarteamVcsAdapter" />
+  <component name="VssVcs" />
+  <component name="com.intellij.jsf.UserDefinedFacesConfigs">
+    <option name="USER_DEFINED_CONFIGS">
+      <value>
+        <list size="0" />
+      </value>
+    </option>
+  </component>
+  <component name="libraryTable" />
+  <component name="uidesigner-configuration">
+    <option name="INSTRUMENT_CLASSES" value="true" />
+    <option name="COPY_FORMS_RUNTIME_TO_OUTPUT" value="true" />
+    <option name="DEFAULT_LAYOUT_MANAGER" value="GridLayoutManager" />
+  </component>
+  <UsedPathMacros />
+</project>
+

=== added directory 'util/fonttool/src'
=== added directory 'util/fonttool/src/org'
=== added directory 'util/fonttool/src/org/gnu'
=== added directory 'util/fonttool/src/org/gnu/grub'
=== added directory 'util/fonttool/src/org/gnu/grub/fonttool'
=== added file 'util/fonttool/src/org/gnu/grub/fonttool/BDFFont.java'
--- util/fonttool/src/org/gnu/grub/fonttool/BDFFont.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/BDFFont.java	2008-07-03 14:08:39 +0000
@@ -0,0 +1,24 @@
+package org.gnu.grub.fonttool;
+
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BDFFont {
+    private Map<Character, BufferedImage> glyphs = new HashMap<Character, BufferedImage>();
+    private int height = 0;
+
+    void putGlyph(char ch, BufferedImage glyph) {
+        glyphs.put(ch, glyph);
+        if (glyph.getHeight() > height)
+            height = glyph.getHeight();
+    }
+
+    public BufferedImage getGlyph(char c) {
+        return glyphs.get(c);
+    }
+
+    public int getHeight() {
+        return height;
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/BDFLoader.java'
--- util/fonttool/src/org/gnu/grub/fonttool/BDFLoader.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/BDFLoader.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,254 @@
+package org.gnu.grub.fonttool;
+
+import java.io.*;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BDFLoader {
+    private final BufferedReader in;
+    private final Font font;
+    private int maxCharWidth;
+    private int maxCharHeight;
+
+    BDFLoader(BufferedReader in) {
+        this.in = in;
+        this.font = new Font();
+        this.maxCharWidth = 0;
+        this.maxCharHeight = 0;
+    }
+
+    public static boolean isBDFFile(String filename) {
+        DataInputStream in = null;
+        try {
+            in = new DataInputStream(new FileInputStream(filename));
+            final String signature = "STARTFONT ";
+            byte[] b = new byte[signature.length()];
+            in.readFully(b);
+            in.close();
+
+            String s = new String(b, "US-ASCII");
+            return signature.equals(s);
+        } catch (IOException e) {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e1) {
+                    // Ignore.
+                }
+            }
+            return false;
+        }
+    }
+
+    public static Font loadFontResource(String resourceName) throws IOException {
+        InputStream in = BDFLoader.class.getClassLoader().getResourceAsStream(resourceName);
+        if (in == null)
+            throw new FileNotFoundException("Font resource " + resourceName + " not found");
+        return loadFontFromStream(in);
+    }
+
+    public static Font loadFontFile(String filename) throws IOException {
+        InputStream in = new FileInputStream(filename);
+        return loadFontFromStream(in);
+    }
+
+    private static Font loadFontFromStream(InputStream inStream) throws IOException {
+        BufferedReader in;
+        try {
+            in = new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Encoding not supported: " + e.getMessage(), e);
+        }
+        return new BDFLoader(in).loadFont();
+    }
+
+    private Font loadFont() throws IOException {
+        loadFontInfo();
+        while (loadChar()) {
+            /* Loop. */
+        }
+
+        font.setMaxCharWidth(maxCharWidth);
+        font.setMaxCharHeight(maxCharHeight);
+        return font;
+    }
+
+    private void loadFontInfo() throws IOException {
+        final Pattern stringSettingPattern = Pattern.compile("^(\\w+)\\s+\"([^\"]+)\"$");
+        String line;
+        // Load the global font information that appears before CHARS.
+        final int UNSET = Integer.MIN_VALUE;
+        font.setAscent(UNSET);
+        font.setDescent(UNSET);
+        font.setFamily("Unknown");
+        font.setBold(false);
+        font.setItalic(false);
+        font.setPointSize(Font.UNKNOWN_POINT_SIZE);
+        do {
+            line = in.readLine();
+            if (line == null)
+                throw new IOException("BDF format error: end of file while " +
+                                      "reading global font information");
+
+            StringTokenizer st = new StringTokenizer(line);
+            if (st.hasMoreTokens()) {
+                String name = st.nextToken();
+                if (name.equals("FONT_ASCENT")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: " +
+                                              "no tokens after " + name);
+                    font.setAscent(Integer.parseInt(st.nextToken()));
+                } else if (name.equals("FONT_DESCENT")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: " +
+                                              "no tokens after " + name);
+                    font.setDescent(Integer.parseInt(st.nextToken()));
+                } else if (name.equals("POINT_SIZE")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: " +
+                                              "no tokens after " + name);
+                    // Divide by 10, since it is stored X10.
+                    font.setPointSize(Integer.parseInt(st.nextToken()) / 10);
+                } else if (name.equals("FAMILY_NAME")) {
+                    Matcher matcher = stringSettingPattern.matcher(line);
+                    if (!matcher.matches())
+                        throw new IOException("BDF format error: " +
+                                              "line doesn't match string " +
+                                              "setting pattern: " + line);
+                    font.setFamily(matcher.group(2));
+                } else if (name.equals("WEIGHT_NAME")) {
+                    Matcher matcher = stringSettingPattern.matcher(line);
+                    if (!matcher.matches())
+                        throw new IOException("BDF format error: " +
+                                              "line doesn't match string " +
+                                              "setting pattern: " + line);
+                    String weightName = matcher.group(2);
+                    font.setBold("bold".equalsIgnoreCase(weightName));
+                } else if (name.equals("SLANT")) {
+                    Matcher matcher = stringSettingPattern.matcher(line);
+                    if (!matcher.matches())
+                        throw new IOException("BDF format error: " +
+                                              "line doesn't match string " +
+                                              "setting pattern: " + line);
+                    String slantType = matcher.group(2);
+                    font.setItalic(!"R".equalsIgnoreCase(slantType));
+                } else if (name.equals("CHARS")) {
+                    // This is the end of the global font information and
+                    // the beginning of the character definitions.
+                    break;
+                } else {
+                    // Skip other fields.
+                }
+            }
+        } while (true);
+
+        if (font.getAscent() == UNSET)
+            throw new IOException("BDF format error: no FONT_ASCENT property");
+        if (font.getDescent() == UNSET)
+            throw new IOException("BDF format error: no FONT_DESCENT property");
+    }
+
+    private boolean loadChar() throws IOException {
+        String line;
+        // Find start of character
+        do {
+            line = in.readLine();
+            if (line == null)
+                return false;
+            StringTokenizer st = new StringTokenizer(line);
+            if (st.hasMoreTokens() && st.nextToken().equals("STARTCHAR")) {
+                if (!st.hasMoreTokens())
+                    throw new IOException("BDF format error: no character name after STARTCHAR");
+                break;
+            }
+        } while (true);
+
+        // Find properties
+        final int UNSET = Integer.MIN_VALUE;
+        int codePoint = UNSET;
+        int bbx = UNSET;
+        int bby = UNSET;
+        int bbox = UNSET;
+        int bboy = UNSET;
+        int dwidth = UNSET;
+        do {
+            line = in.readLine();
+            if (line == null)
+                return false;
+            StringTokenizer st = new StringTokenizer(line);
+            if (st.hasMoreTokens()) {
+                String field = st.nextToken();
+                if (field.equals("ENCODING")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: no encoding # after ENCODING");
+                    String codePointStr = st.nextToken();
+                    codePoint = Integer.parseInt(codePointStr);
+                } else if (field.equals("BBX")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: no tokens after BBX");
+                    bbx = Integer.parseInt(st.nextToken());
+                    bby = Integer.parseInt(st.nextToken());
+                    bbox = Integer.parseInt(st.nextToken());
+                    bboy = Integer.parseInt(st.nextToken());
+                } else if (field.equals("DWIDTH")) {
+                    if (!st.hasMoreTokens())
+                        throw new IOException("BDF format error: no tokens after DWIDTH");
+                    dwidth = Integer.parseInt(st.nextToken());
+                    int dwidthY = Integer.parseInt(st.nextToken());
+                    // The DWIDTH Y value should be zero for any normal font.
+                    if (dwidthY != 0) {
+                        throw new IOException("BDF format error: dwidth Y value" +
+                                              "is nonzero (" + dwidthY + ") " +
+                                              "for char " + codePoint + ".");
+                    }
+                } else if (field.equals("BITMAP")) {
+                    break; // now read the bitmap
+                }
+            }
+        } while (true);
+
+        if (codePoint == UNSET)
+            throw new IOException("BDF format error: " +
+                                  "no code point set");
+        if (bbx == UNSET || bby == UNSET)
+            throw new IOException("BDF format error: " +
+                                  "bbx/bby missing: " + bbx + ", " + bby +
+                                  " for char " + codePoint);
+
+        if (bbox == UNSET || bboy == UNSET)
+            throw new IOException("BDF format error: " +
+                                  "bbox/bboy missing: " + bbox + ", " + bboy +
+                                  " for char " + codePoint);
+
+        if (dwidth == UNSET)
+            throw new IOException("BDF format error: " +
+                                  "dwidth missing for char " + codePoint);
+
+        final int glyphWidth = bbx;
+        final int glyphHeight = bby;
+        if (glyphWidth > maxCharWidth)
+            maxCharWidth = glyphWidth;
+        if (glyphHeight > maxCharHeight)
+            maxCharHeight = glyphHeight;
+
+        // Read the bitmap
+        Glyph glyph = new Glyph(codePoint, glyphWidth, glyphHeight, bbox, bboy, dwidth);
+        for (int y = 0; y < glyphHeight; y++) {
+            line = in.readLine();
+            if (line == null)
+                return false;
+            for (int b = 0; b < line.length(); b++) {
+                int v = Integer.parseInt(Character.toString(line.charAt(b)), 16);
+                for (int x = b * 4, i = 0; i < 4 && x < glyphWidth; x++, i++) {
+                    boolean set = (v & 0x8) != 0;
+                    v <<= 1;
+                    glyph.setPixel(x, y, set);
+                }
+            }
+        }
+
+        font.putGlyph(codePoint, glyph);
+        return true;
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/CharDefs.java'
--- util/fonttool/src/org/gnu/grub/fonttool/CharDefs.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/CharDefs.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,135 @@
+package org.gnu.grub.fonttool;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.TreeMap;
+
+class CharDefs {
+    private boolean debug = "1".equals(System.getProperty("fonttool.debug"));
+    private TreeMap<Integer, Glyph> glyphs;
+    private ByteArrayOutputStream charDefsData;
+    private int maxCharWidth;
+    private int maxCharHeight;
+    private HashMap<Integer, CharStorageInfo> charIndex;
+
+    public CharDefs(Font font) {
+        this.glyphs = font.getGlyphs();
+        this.charIndex = null;
+        this.charDefsData = null;
+
+        calculateMaxSizes();
+    }
+
+    private void calculateMaxSizes() {
+        maxCharWidth = 0;
+        maxCharHeight = 0;
+        for (Glyph glyph : glyphs.values()) {
+            final int w = glyph.getWidth();
+            final int h = glyph.getHeight();
+            if (w > maxCharWidth)
+                maxCharWidth = w;
+            if (h > maxCharHeight)
+                maxCharHeight = h;
+        }
+    }
+
+    void buildDefinitions() {
+        charIndex = new HashMap<Integer, CharStorageInfo>();
+        HashMap<CharDef, Long> charDefIndex = new HashMap<CharDef, Long>();
+        charDefsData = new ByteArrayOutputStream();
+        DataOutputStream charDefs = new DataOutputStream(charDefsData);
+        try {
+            // Loop through all the glyphs, writing the glyph data to the
+            // in-memory byte stream, collapsing duplicate glyphs, and
+            // constructing index information.
+            for (Glyph glyph : glyphs.values()) {
+                CharDef charDef = new CharDef(glyph.getWidth(),
+                                              glyph.getHeight(),
+                                              glyph.getBitmap());
+
+                if (charDefIndex.containsKey(charDef)) {
+                    // Use already-written glyph.
+                    if (debug)
+                        System.out.printf("Duplicate glyph for character U+%04X%n",
+                                          glyph.getCodePoint());
+                    final int charOffset = charDefIndex.get(charDef).intValue();
+                    final CharStorageInfo info =
+                            new CharStorageInfo(glyph.getCodePoint(), charOffset);
+                    charIndex.put(glyph.getCodePoint(), info);
+                } else {
+                    // Write glyph data.
+                    final int charOffset = charDefs.size();
+                    final CharStorageInfo info =
+                            new CharStorageInfo(glyph.getCodePoint(), charOffset);
+                    charIndex.put(glyph.getCodePoint(), info);
+
+                    charDefIndex.put(charDef, (long) charOffset);
+
+                    charDefs.writeShort(glyph.getWidth());
+                    charDefs.writeShort(glyph.getHeight());
+                    charDefs.writeShort(glyph.getBbox());
+                    charDefs.writeShort(glyph.getBboy());
+                    charDefs.writeShort(glyph.getDeviceWidth());
+                    charDefs.write(glyph.getBitmap());
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Error writing to in-memory byte stream", e);
+        }
+    }
+
+    public int getMaxCharWidth() {
+        return maxCharWidth;
+    }
+
+    public int getMaxCharHeight() {
+        return maxCharHeight;
+    }
+
+    public HashMap<Integer, CharStorageInfo> getCharIndex() {
+        if (charIndex == null) throw new IllegalStateException();
+        return charIndex;
+    }
+
+    public byte[] getDefinitionData() {
+        if (charDefsData == null) throw new IllegalStateException();
+        return charDefsData.toByteArray();
+    }
+
+
+    private static class CharDef {
+        private final int width;
+        private final int height;
+        private final byte[] data;
+
+        public CharDef(int width, int height, byte[] data) {
+            this.width = width;
+            this.height = height;
+            this.data = data;
+        }
+
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            CharDef charDef = (CharDef) o;
+
+            if (height != charDef.height) return false;
+            if (width != charDef.width) return false;
+            if (!Arrays.equals(data, charDef.data)) return false;
+
+            return true;
+        }
+
+        public int hashCode() {
+            int result;
+            result = width;
+            result = 31 * result + height;
+            result = 31 * result + Arrays.hashCode(data);
+            return result;
+        }
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/CharMatrix.java'
--- util/fonttool/src/org/gnu/grub/fonttool/CharMatrix.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/CharMatrix.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,139 @@
+package org.gnu.grub.fonttool;
+
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.*;
+
+public class CharMatrix extends JComponent {
+    private Font charFont;
+    private int zoom = 1;
+    private int startingChar;
+    private Map<Rectangle, Integer> glyphLocations = new HashMap<Rectangle, Integer>();
+    private GlyphSelectionListener glyphSelectionListener;
+    private Point mouseLocation;
+
+    public interface GlyphSelectionListener {
+        void glyphSelected(int codePoint);
+    }
+
+    public CharMatrix() {
+        addMouseListener(new MouseAdapter() {
+            public void mousePressed(MouseEvent e) {
+                int codePoint = getCodePointForGlyphAt(e.getPoint());
+                if (codePoint != -1) {
+                    if (glyphSelectionListener != null)
+                        glyphSelectionListener.glyphSelected(codePoint);
+                }
+            }
+
+            public void mouseExited(MouseEvent e) {
+                mouseLocation = null;
+                repaint();
+            }
+        });
+
+        addMouseMotionListener(new MouseMotionAdapter() {
+            public void mouseMoved(MouseEvent e) {
+                mouseLocation = e.getPoint();
+                repaint();
+            }
+        });
+    }
+
+    public void setGlyphSelectionListener(GlyphSelectionListener listener) {
+        this.glyphSelectionListener = listener;
+    }
+
+    public Font getCharFont() {
+        return charFont;
+    }
+
+    public void setCharFont(Font font) {
+        this.charFont = font;
+        repaint();
+    }
+
+    public int getZoom() {
+        return zoom;
+    }
+
+    public void setZoom(int zoom) {
+        this.zoom = zoom;
+        repaint();
+    }
+
+    public int getStartingChar() {
+        return startingChar;
+    }
+
+    public void setStartingChar(int startingChar) {
+        this.startingChar = startingChar;
+        repaint();
+    }
+
+    public int getCodePointForGlyphAt(Point p) {
+        for (Rectangle rectangle : glyphLocations.keySet()) {
+            if (rectangle.contains(p))
+                return glyphLocations.get(rectangle);
+        }
+        return -1;
+    }
+
+    protected void paintComponent(Graphics g) {
+        glyphLocations.clear();
+
+        if (charFont == null)
+            return;
+
+        int w = getWidth();
+        int h = getHeight();
+        int maxCharWidth = charFont.getMaxCharWidth();
+        int maxCharHeight = charFont.getMaxCharHeight();
+        int space = 2;
+        int charsPerRow = w / (maxCharWidth + space);
+        int rows = h / (maxCharHeight + space);
+
+        Rectangle highlightBounds = null;
+        int codePoint = startingChar;
+        int y = 3 + charFont.getAscent();   // Point y to the baseline.
+        for (int row = 0; row < rows; row++) {
+            int x = 3;
+            for (int col = 0; col < charsPerRow; col++) {
+                Glyph glyph = charFont.getGlyph(codePoint);
+
+                if (glyph != null) {
+                    Rectangle charBounds =
+                            CharView.drawGlyph(g, charFont, glyph, x, y, zoom, getForeground());
+                    // Expand the bounding box for a bigger clickable area.
+                    final int boundsPad = 1;
+                    charBounds.x -= boundsPad;
+                    charBounds.y -= boundsPad;
+                    charBounds.width += 2 * boundsPad;
+                    charBounds.height += 2 * boundsPad;
+                    glyphLocations.put(charBounds, codePoint);
+                    if (mouseLocation != null && charBounds.contains(mouseLocation)) {
+                        highlightBounds = charBounds;
+                    }
+                }
+                x += maxCharWidth + space;
+                codePoint++;
+            }
+
+            y += maxCharHeight + space;
+        }
+
+        if (highlightBounds != null) {
+            g.setColor(Color.blue);
+            Graphics2D g2 = (Graphics2D) g;
+            g2.setStroke(new BasicStroke(3f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 2f));
+            g2.draw(new Rectangle(highlightBounds.x - 2, highlightBounds.y - 2,
+                                  highlightBounds.width + 3, highlightBounds.height + 3));
+            g2.setStroke(new BasicStroke(1f));
+        }
+
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/CharStorageInfo.java'
--- util/fonttool/src/org/gnu/grub/fonttool/CharStorageInfo.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/CharStorageInfo.java	2008-07-03 14:08:39 +0000
@@ -0,0 +1,19 @@
+package org.gnu.grub.fonttool;
+
+class CharStorageInfo {
+    private final int codePoint;
+    private final int fileOffset;
+
+    public CharStorageInfo(int codePoint, int fileOffset) {
+        this.codePoint = codePoint;
+        this.fileOffset = fileOffset;
+    }
+
+    public int getCodePoint() {
+        return codePoint;
+    }
+
+    public int getFileOffset() {
+        return fileOffset;
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/CharView.java'
--- util/fonttool/src/org/gnu/grub/fonttool/CharView.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/CharView.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,101 @@
+package org.gnu.grub.fonttool;
+
+import java.awt.*;
+import java.util.Formatter;
+import javax.swing.*;
+
+public class CharView extends JComponent {
+    private Font charFont = null;
+    private Glyph glyph = null;
+    private int zoom = 1;
+
+    public Font getCharFont() {
+        return charFont;
+    }
+
+    public void setCharFont(Font charFont) {
+        this.charFont = charFont;
+    }
+
+    public Glyph getGlyph() {
+        return glyph;
+    }
+
+    public void setGlyph(Glyph glyph) {
+        this.glyph = glyph;
+        repaint();
+    }
+
+    public void setZoom(int zoom) {
+        this.zoom = zoom;
+    }
+
+    public Dimension getPreferredSize() {
+        if (glyph == null)
+            return new Dimension(1, 1);
+        return new Dimension(glyph.getWidth() * zoom, glyph.getHeight() * zoom);
+    }
+
+    protected void paintComponent(Graphics g) {
+        if (glyph == null) {
+            // Draw a gray 'X' indicating no character selected.
+            g.setColor(Color.gray);
+            g.drawLine(0, 0, getWidth() - 1, getHeight() - 1);
+            g.drawLine(getWidth(), 0, 0, getHeight() - 1);
+            return;
+        }
+
+        final int x0 = (getWidth() - glyph.getWidth() * zoom) / 2;
+        final int y0 = getHeight() / 2;
+        drawGlyph(g, charFont, glyph, x0, y0, zoom, getForeground());
+
+        g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));
+        FontMetrics fm = g.getFontMetrics();
+        Formatter f = new Formatter();
+        f.format("U+%04X", glyph.getCodePoint());
+        String str = f.toString();
+        g.drawString(str,
+                     (getWidth() - fm.stringWidth(str)) / 2,
+                     getHeight() - fm.getHeight());
+    }
+
+    /**
+     * Draw the specified glyph with its baseline at y0 and the horizontal
+     * start at x0.
+     */
+    static Rectangle drawGlyph(Graphics g, Font font, Glyph glyph, int startX, int baselineY, int zoom, Color fg) {
+        // Adjust (x0, y0) so that it puts the bitmap at the right location.
+        final int offsetX = zoom * glyph.getBbox();
+        final int offsetY = zoom * glyph.getBboy();
+        final int bitmapLeft = startX + offsetX;
+        final int bitmapBottom = baselineY - offsetY;
+        final int bitmapTop = bitmapBottom - zoom * glyph.getHeight();
+
+        // Draw a gray box around the glyph bounds.
+        g.setColor(Color.lightGray);
+        g.drawRect(bitmapLeft - 1, bitmapTop - 1,
+                   glyph.getWidth() * zoom + 1, zoom * glyph.getHeight() + 1);
+
+        // Draw the baseline
+        g.setColor(new Color(110, 110, 255));
+        g.drawLine(startX, baselineY, startX + zoom * glyph.getDeviceWidth(), baselineY);
+
+        // Draw the glyph.
+        g.setColor(fg);
+        byte[] bitmap = glyph.getBitmap();
+        int bitIndex = 0;
+        for (int y = 0; y < glyph.getHeight(); y++) {
+            for (int x = 0; x < glyph.getWidth(); x++, bitIndex++) {
+                int byteIndex = bitIndex / 8;
+                int bitShift = bitIndex % 8;
+                byte b = bitmap[byteIndex];
+                boolean bitValue = (b & (0x80 >>> bitShift)) != 0;
+                if (bitValue) {
+                    g.fillRect(bitmapLeft + x * zoom, bitmapTop + y * zoom, zoom, zoom);
+                }
+            }
+        }
+
+        return new Rectangle(bitmapLeft, bitmapTop, zoom * glyph.getWidth(), zoom * glyph.getHeight());
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/Converter.java'
--- util/fonttool/src/org/gnu/grub/fonttool/Converter.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/Converter.java	2008-07-03 14:08:39 +0000
@@ -0,0 +1,78 @@
+package org.gnu.grub.fonttool;
+
+import java.io.IOException;
+
+/**
+ * Program to convert BDF fonts into PFF2 fonts for use with GRUB.
+ */
+public class Converter {
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            printUsageAndExit();
+        }
+
+        String in = null;
+        String out = null;
+
+        try {
+            for (String arg : args) {
+                if (arg.startsWith("--")) {
+                    String option;
+                    String value;
+                    int equalsPos = arg.indexOf('=');
+                    if (equalsPos < 0) {
+                        option = arg.substring(2);
+                        value = null;
+                    } else {
+                        option = arg.substring(2, equalsPos);
+                        value = arg.substring(equalsPos + 1);
+                    }
+
+                    if ("in".equals(option)) {
+                        if (value == null)
+                            throw new CommandLineException(option + " option requires a value.");
+                        in = value;
+                    } else if ("out".equals(option)) {
+                        if (value == null)
+                            throw new CommandLineException(option + " option requires a value.");
+                        out = value;
+                    }
+                } else {
+                    throw new CommandLineException("Non-option argument `" + arg + "'.");
+                }
+            }
+            if (in == null || out == null) {
+                throw new CommandLineException("Both --in=X and --out=Y must be specified.");
+            }
+        } catch (CommandLineException e) {
+            System.err.println("Error: " + e.getMessage());
+            System.exit(1);
+        }
+
+        try {
+            // Read BDF.
+            Font font = BDFLoader.loadFontFile(in);
+
+            // Write PFF2.
+            new PFF2Writer(out).writeFont(font);
+        } catch (IOException e) {
+            System.err.println("I/O error converting font: " + e);
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static class CommandLineException extends Exception {
+        public CommandLineException(String message) {
+            super(message);
+        }
+    }
+
+    private static void printUsageAndExit() {
+        System.err.println("GNU GRUB Font Conversion Tool");
+        System.err.println();
+        System.err.println("Usage: Converter --in=IN.bdf --out=OUT.pf2");
+        System.err.println();
+        System.exit(1);
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/FileFormatException.java'
--- util/fonttool/src/org/gnu/grub/fonttool/FileFormatException.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/FileFormatException.java	2008-07-03 14:08:39 +0000
@@ -0,0 +1,9 @@
+package org.gnu.grub.fonttool;
+
+import java.io.IOException;
+
+public class FileFormatException extends IOException {
+    public FileFormatException(String msg) {
+        super(msg);
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/Font.java'
--- util/fonttool/src/org/gnu/grub/fonttool/Font.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/Font.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,106 @@
+package org.gnu.grub.fonttool;
+
+import java.util.TreeMap;
+
+public class Font {
+    public static final int UNKNOWN_POINT_SIZE = -1;
+
+    private TreeMap<Integer, Glyph> glyphs;
+    private String family;
+    private boolean bold;
+    private boolean italic;
+    private int pointSize;
+    private int maxCharWidth;
+    private int maxCharHeight;
+    private int ascent;
+    private int descent;
+
+    public Font() {
+        glyphs = new TreeMap<Integer, Glyph>();
+    }
+
+    public String getFamily() {
+        return family;
+    }
+
+    public void setFamily(String family) {
+        this.family = family;
+    }
+
+    public boolean isBold() {
+        return bold;
+    }
+
+    public void setBold(boolean bold) {
+        this.bold = bold;
+    }
+
+    public boolean isItalic() {
+        return italic;
+    }
+
+    public void setItalic(boolean italic) {
+        this.italic = italic;
+    }
+
+    public int getPointSize() {
+        return pointSize;
+    }
+
+    public void setPointSize(int pointSize) {
+        this.pointSize = pointSize;
+    }
+
+    public int getMaxCharWidth() {
+        return maxCharWidth;
+    }
+
+    public void setMaxCharWidth(int maxCharWidth) {
+        this.maxCharWidth = maxCharWidth;
+    }
+
+    public int getMaxCharHeight() {
+        return maxCharHeight;
+    }
+
+    public void setMaxCharHeight(int maxCharHeight) {
+        this.maxCharHeight = maxCharHeight;
+    }
+
+    public int getAscent() {
+        return ascent;
+    }
+
+    public void setAscent(int ascent) {
+        this.ascent = ascent;
+    }
+
+    public int getDescent() {
+        return descent;
+    }
+
+    public void setDescent(int descent) {
+        this.descent = descent;
+    }
+
+    public void putGlyph(int codePoint, Glyph glyph) {
+        glyphs.put(codePoint, glyph);
+    }
+
+    public TreeMap<Integer, Glyph> getGlyphs() {
+        return glyphs;
+    }
+
+    public Glyph getGlyph(int codePoint) {
+        return glyphs.get(codePoint);
+    }
+
+    public String getStandardName() {
+        StringBuilder name = new StringBuilder(getFamily());
+        if (isBold()) name.append(" Bold");
+        if (isItalic()) name.append(" Italic");
+        name.append(' ');
+        name.append(getPointSize());
+        return name.toString();
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/Glyph.java'
--- util/fonttool/src/org/gnu/grub/fonttool/Glyph.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/Glyph.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,83 @@
+package org.gnu.grub.fonttool;
+
+public class Glyph {
+    private final int codePoint;
+    private final int width;
+    private final int height;
+
+    // These define the amounts to shift the character bitmap by
+    // before drawing it.  See
+    //    http://www.adobe.com/devnet/font/pdfs/5005.BDF_Spec.pdf
+    // and
+    //    http://www.linuxbabble.com/documentation/x/bdf/
+    // for explanatory figures.
+    private final int bbox;
+    private final int bboy;
+
+    // Number of pixels to advance horizontally from this character's origin
+    // to the origin of the next character.
+    private final int deviceWidth;
+
+    // Row-major order, no padding.  Rows can break within a byte.
+    // MSb is first (leftmost/uppermost) pixel.
+    private final byte[] bitmap;
+
+    public Glyph(int codePoint, int width, int height, int bbox, int bboy, int deviceWidth) {
+        this(codePoint, width, height, bbox, bboy, deviceWidth,
+             new byte[(width * height + 7) / 8]);
+    }
+
+    public Glyph(int codePoint, int width, int height,
+                 int bbox, int bboy, int deviceWidth,
+                 byte[] bitmap) {
+        this.codePoint = codePoint;
+        this.width = width;
+        this.height = height;
+        this.bboy = bboy;
+        this.bbox = bbox;
+        this.deviceWidth = deviceWidth;
+        this.bitmap = bitmap;
+    }
+
+    public void setPixel(int x, int y, boolean value) {
+        if (x < 0 || y < 0 || x >= width || y >= height)
+            throw new IllegalArgumentException(
+                    "Invalid pixel location (" + x + ", " + y + ") for "
+                    + width + "x" + height + " glyph");
+
+        int bitIndex = y * width + x;
+        int byteIndex = bitIndex / 8;
+        int bitPos = bitIndex % 8;
+        int v = value ? 0x80 >>> bitPos : 0;
+        int mask = ~(0x80 >>> bitPos);
+        bitmap[byteIndex] = (byte) ((bitmap[byteIndex] & mask) | v);
+    }
+
+    public int getCodePoint() {
+        return codePoint;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public int getBbox() {
+        return bbox;
+    }
+
+    public int getBboy() {
+        return bboy;
+    }
+
+    public int getDeviceWidth() {
+        return deviceWidth;
+    }
+
+    public byte[] getBitmap() {
+        return bitmap;
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/PFF2Loader.java'
--- util/fonttool/src/org/gnu/grub/fonttool/PFF2Loader.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/PFF2Loader.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,203 @@
+package org.gnu.grub.fonttool;
+
+import java.io.EOFException;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.charset.Charset;
+
+/**
+ * Load a PFF2 font completely into memory as an instance of Font.
+ */
+public class PFF2Loader {
+    private static final int debug
+            = Integer.parseInt(System.getProperty("fonttool.debug", "0"));
+
+    private RandomAccessFile f;
+    private Font font;
+
+    private PFF2Loader(String filename) throws FileNotFoundException {
+        f = new RandomAccessFile(filename, "r");
+        font = new Font();
+    }
+
+    public static boolean isPFF2File(String filename) {
+        RandomAccessFile f = null;
+        boolean isFont = false;
+        try {
+            f = new RandomAccessFile(filename, "r");
+            byte[] sectionNameBytes = new byte[4];
+            f.readFully(sectionNameBytes);
+            String sectionName = new String(sectionNameBytes, "US-ASCII");
+            if (sectionName.equals(PFF2Sections.FILE)) {
+                final String expectedType = "PFF2";
+                int len = f.readInt();
+                if (len == expectedType.length()) {
+                    byte[] typeBytes = new byte[len];
+                    f.readFully(typeBytes);
+                    String type = new String(typeBytes, "US-ASCII");
+                    if (type.equals(expectedType)) {
+                        isFont = true;
+                    }
+                }
+            }
+            f.close();
+        } catch (IOException e) {
+            if (f != null) {
+                try {
+                    f.close();
+                } catch (IOException e1) {
+                    // Ignore.
+                }
+            }
+        }
+
+        return isFont;
+    }
+
+    public static Font loadFontFile(String filename) throws IOException {
+        PFF2Loader loader = new PFF2Loader(filename);
+        loader.loadFont();
+        return loader.getFont();
+    }
+
+    private void loadFont() throws IOException {
+        String s;
+        s = openSection();
+        if (!PFF2Sections.FILE.equals(s))
+            throw new FileFormatException(
+                    "First PFF2 section must be FILE but is `" + s + "'.");
+
+        s = readCompleteSectionAsString();
+        if (!"PFF2".equals(s))
+            throw new FileFormatException("Unsupported file type `" + s + "'.");
+
+        font.setFamily("Unnamed");
+        font.setPointSize(Font.UNKNOWN_POINT_SIZE);
+        try {
+            if (debug >= 1) System.out.println("Loading font information...");
+            boolean doneLoadingInfo = false;
+            while (!doneLoadingInfo) {
+                s = openSection();
+                int sectionLength = f.readInt();
+                if (debug >= 2)
+                    System.out.println("Section: " + s + " length: " + sectionLength);
+                if (s.equals(PFF2Sections.MAX_CHAR_WIDTH)) {
+                    int maxCharWidth = readSectionContentsAsUShort(sectionLength);
+                    font.setMaxCharWidth(maxCharWidth);
+                } else if (s.equals(PFF2Sections.MAX_CHAR_HEIGHT)) {
+                    int maxCharHeight = readSectionContentsAsUShort(sectionLength);
+                    font.setMaxCharHeight(maxCharHeight);
+                } else if (s.equals(PFF2Sections.FONT_POINT_SIZE)) {
+                    int pointSize = readSectionContentsAsUShort(sectionLength);
+                    font.setPointSize(pointSize);
+                } else if (s.equals(PFF2Sections.FONT_ASCENT)) {
+                    int ascent = readSectionContentsAsUShort(sectionLength);
+                    font.setAscent(ascent);
+                } else if (s.equals(PFF2Sections.FONT_DESCENT)) {
+                    int descent = readSectionContentsAsUShort(sectionLength);
+                    font.setDescent(descent);
+                } else if (s.equals(PFF2Sections.FONT_NAME)) {
+                    String fontName = readSectionContentsAsString(sectionLength);
+                    if (debug >= 1)
+                        System.out.println("Loaded font: " + fontName);
+                } else if (s.equals(PFF2Sections.FONT_FAMILY)) {
+                    font.setFamily(readSectionContentsAsString(sectionLength));
+                } else if (s.equals(PFF2Sections.FONT_WEIGHT)) {
+                    String weightString = readSectionContentsAsString(sectionLength);
+                    font.setBold(weightString.equalsIgnoreCase("bold"));
+                } else if (s.equals(PFF2Sections.FONT_SLANT)) {
+                    String slantString = readSectionContentsAsString(sectionLength);
+                    font.setItalic(slantString.equalsIgnoreCase("italic"));
+                } else if (s.equals(PFF2Sections.CHAR_INDEX)) {
+                    loadCharsFromIndex(sectionLength);
+                } else if (s.equals(PFF2Sections.REMAINDER_IS_DATA)) {
+                    doneLoadingInfo = true;
+                } else {
+                    // If the section is not handled, then we just skip it.
+                    if (f.skipBytes(sectionLength) != sectionLength) {
+                        System.err.println("Warning: Could not skip "
+                                           + sectionLength
+                                           + " bytes for section `" + s + "'.");
+                    }
+                }
+            }
+        } catch (EOFException eofException) {
+            // End of file; done reading font.
+        }
+        f.close();
+    }
+
+    private void loadCharsFromIndex(int sectionLength) throws IOException {
+        long indexSectionEnd = f.getFilePointer() + sectionLength;
+        try {
+            while (f.getFilePointer() < indexSectionEnd) {
+                int codePoint = f.readInt();
+                int storageFlags = f.readUnsignedByte();
+                int offset = f.readInt();
+
+                if ((storageFlags & 0x07) == 0) {
+                    Glyph g = loadUncompressedGlyph(codePoint, offset);
+                    font.putGlyph(codePoint, g);
+                }
+            }
+        } catch (EOFException eofException) {
+            // End of file; simple return.
+        }
+    }
+
+    private Glyph loadUncompressedGlyph(int codePoint, int fileOffset) throws IOException {
+        if (debug >= 3)
+            System.out.printf("Loading uncompressed glyph U+%04X at %d%n", codePoint, fileOffset);
+
+        long savedPos = f.getFilePointer();
+
+        f.seek(fileOffset);
+        int width = f.readUnsignedShort();
+        int height = f.readUnsignedShort();
+        int offsetX = f.readShort();
+        int offsetY = f.readShort();
+        int deviceWidth = f.readShort();
+        if (debug >= 3) System.out.println("  Size=" + width + "x" + height
+                                           + " offset=(" + offsetX + ", " + offsetY
+                                           + ") dWidth=" + deviceWidth);
+        byte[] bitmap = new byte[(width * height + 7) / 8];
+        f.readFully(bitmap);
+
+        f.seek(savedPos);
+        return new Glyph(codePoint, width, height,
+                         offsetX, offsetY, deviceWidth, bitmap);
+    }
+
+    private int readSectionContentsAsUShort(int sectionLength) throws IOException {
+        if (sectionLength != 2)
+            throw new FileFormatException(
+                    "For uint16 section, expected 2 bytes but length is "
+                    + sectionLength + ".");
+        return f.readUnsignedShort();
+    }
+
+    private String openSection() throws IOException {
+        byte[] b = new byte[4];
+        f.readFully(b);
+        return new String(b, Charset.forName("US-ASCII"));
+    }
+
+    private String readCompleteSectionAsString() throws IOException {
+        int n = f.readInt();
+        return readSectionContentsAsString(n);
+    }
+
+    private String readSectionContentsAsString(int n) throws IOException {
+        StringBuilder buf = new StringBuilder();
+        while (n-- != 0) {
+            char c = (char) (f.readByte() & 0xFF);
+            buf.append(c);
+        }
+        return buf.toString();
+    }
+
+    public Font getFont() {
+        return font;
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/PFF2Sections.java'
--- util/fonttool/src/org/gnu/grub/fonttool/PFF2Sections.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/PFF2Sections.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,19 @@
+package org.gnu.grub.fonttool;
+
+/**
+ * Section name constants for the PFF2 file format.
+ */
+public class PFF2Sections {
+    static final String FILE = "FILE";
+    static final String FONT_NAME = "NAME";
+    static final String FONT_FAMILY = "FAMI";
+    static final String FONT_WEIGHT = "WEIG";
+    static final String FONT_SLANT = "SLAN";
+    static final String FONT_POINT_SIZE = "PTSZ";
+    static final String MAX_CHAR_WIDTH = "MAXW";
+    static final String MAX_CHAR_HEIGHT = "MAXH";
+    static final String FONT_ASCENT = "ASCE";
+    static final String FONT_DESCENT = "DESC";
+    static final String CHAR_INDEX = "CHIX";
+    static final String REMAINDER_IS_DATA = "DATA";
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/PFF2Writer.java'
--- util/fonttool/src/org/gnu/grub/fonttool/PFF2Writer.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/PFF2Writer.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,133 @@
+package org.gnu.grub.fonttool;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+// TODO Add DEFLATE compressed blocks of characters.
+public class PFF2Writer {
+    private RandomAccessFile f;
+    private String currentSection;
+    private long currentSectionStart;
+
+    public PFF2Writer(String filename) throws FileNotFoundException {
+        this.f = new RandomAccessFile(filename, "rw");
+        this.currentSection = null;
+        this.currentSectionStart = -1;
+    }
+
+    public void writeFont(Font font) throws IOException {
+        // Write file type ID header.
+        writeSection(PFF2Sections.FILE, "PFF2");
+
+        writeSection(PFF2Sections.FONT_NAME, font.getStandardName());
+        writeSection(PFF2Sections.FONT_FAMILY, font.getFamily());
+        writeSection(PFF2Sections.FONT_WEIGHT, font.isBold() ? "bold" : "normal");
+        writeSection(PFF2Sections.FONT_SLANT, font.isItalic() ? "italic" : "normal");
+        if (font.getPointSize() != Font.UNKNOWN_POINT_SIZE)
+            writeShortSection(PFF2Sections.FONT_POINT_SIZE, font.getPointSize());
+
+        // Construct character definitions.
+        CharDefs charDefs = new CharDefs(font);
+        charDefs.buildDefinitions();
+
+        // Write max character width and height metrics.
+        writeShortSection(PFF2Sections.MAX_CHAR_WIDTH, charDefs.getMaxCharWidth());
+        writeShortSection(PFF2Sections.MAX_CHAR_HEIGHT, charDefs.getMaxCharHeight());
+        writeShortSection(PFF2Sections.FONT_ASCENT, font.getAscent());
+        writeShortSection(PFF2Sections.FONT_DESCENT, font.getDescent());
+
+        // Write character index with pointers to the character definitions.
+        beginSection(PFF2Sections.CHAR_INDEX);
+
+        // Determine the size of the index, so we can properly refer to the
+        // character definition offset in the index.  The actual number of
+        // bytes written is compared to the calculated value to ensure we
+        // are correct.
+        final int indexStart = (int) f.getFilePointer();
+        final int calculatedIndexLength =
+                font.getGlyphs().size() * (4 + 1 + 4);
+        final int charDefStart = indexStart + calculatedIndexLength + 8;
+
+        for (CharStorageInfo storageInfo : charDefs.getCharIndex().values()) {
+            f.writeInt(storageInfo.getCodePoint());
+            f.writeByte(0);   // Storage flags: bits 1..0 = 00b : uncompressed.
+            f.writeInt(charDefStart + storageInfo.getFileOffset());
+        }
+
+        final int indexEnd = (int) f.getFilePointer();
+        if (indexEnd - indexStart != calculatedIndexLength) {
+            throw new RuntimeException("Incorrect index length calculated, calc="
+                                       + calculatedIndexLength
+                                       + " actual=" + (indexEnd - indexStart));
+        }
+        endSection(PFF2Sections.CHAR_INDEX);
+
+        f.writeBytes(PFF2Sections.REMAINDER_IS_DATA);
+        f.writeInt(-1);     // Data takes up the rest of the file.
+        f.write(charDefs.getDefinitionData());
+
+        f.close();
+    }
+
+    private void beginSection(String sectionName) throws IOException {
+        verifyOkToBeginSection(sectionName);
+
+        f.writeBytes(sectionName);
+        f.writeInt(-1);     // Placeholder for the section length.
+        currentSection = sectionName;
+        currentSectionStart = f.getFilePointer();
+    }
+
+    private void endSection(String sectionName) throws IOException {
+        verifyOkToEndSection(sectionName);
+
+        long sectionEnd = f.getFilePointer();
+        long sectionLength = sectionEnd - currentSectionStart;
+        f.seek(currentSectionStart - 4);
+        f.writeInt((int) sectionLength);
+        f.seek(sectionEnd);
+        currentSection = null;
+        currentSectionStart = -1;
+    }
+
+    private void verifyOkToBeginSection(String sectionName) {
+        if (sectionName.length() != 4)
+            throw new IllegalArgumentException(
+                    "Section names must be 4 characters: `" + sectionName + "'.");
+        if (currentSection != null)
+            throw new IllegalStateException(
+                    "Attempt to start `" + sectionName
+                    + "' section before ending the previous section `"
+                    + currentSection + "'.");
+    }
+
+    private void verifyOkToEndSection(String sectionName) {
+        if (sectionName.length() != 4)
+            throw new IllegalStateException("Invalid section name '" + sectionName
+                                            + "'; must be 4 characters.");
+        if (currentSection == null)
+            throw new IllegalStateException(
+                    "Attempt to end section `" + sectionName
+                    + "' when no section active.");
+        if (!sectionName.equals(currentSection))
+            throw new IllegalStateException(
+                    "Attempt to end `" + sectionName
+                    + "' section during active section `"
+                    + currentSection + "'.");
+    }
+
+    private void writeSection(String sectionName, String contents) throws IOException {
+        verifyOkToBeginSection(sectionName);
+        f.writeBytes(sectionName);
+        f.writeInt(contents.length());
+        f.writeBytes(contents);
+    }
+
+    private void writeShortSection(String sectionName, int value) throws IOException {
+        verifyOkToBeginSection(sectionName);
+        f.writeBytes(sectionName);
+        f.writeInt(2);
+        f.writeShort(value);
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/Viewer.java'
--- util/fonttool/src/org/gnu/grub/fonttool/Viewer.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/Viewer.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,135 @@
+package org.gnu.grub.fonttool;
+
+import java.io.File;
+import java.io.IOException;
+import javax.swing.*;
+
+/**
+ * Program to view fonts.
+ * <p/>
+ * Supports PFF2 and BDF format font files.
+ */
+public class Viewer {
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            printUsageAndExit();
+        }
+
+        boolean verbose = false;
+        String format = null;
+        String filename = null;
+
+        try {
+            for (String arg : args) {
+                if (arg.startsWith("--")) {
+                    String option;
+                    String value;
+                    int equalsPos = arg.indexOf('=');
+                    if (equalsPos < 0) {
+                        option = arg.substring(2);
+                        value = null;
+                    } else {
+                        option = arg.substring(2, equalsPos);
+                        value = arg.substring(equalsPos + 1);
+                    }
+
+                    if ("format".equals(option)) {
+                        if (value == null)
+                            throw new CommandLineException(option + " option requires a value.");
+                        format = value;
+                    } else if ("verbose".equals(option)) {
+                        verbose = true;
+                    }
+                } else {
+                    if (filename == null) {
+                        filename = arg;
+                    } else {
+                        throw new CommandLineException(
+                                "Extra argument after filename: `" + arg + "'.");
+                    }
+                }
+            }
+            if (filename == null) {
+                throw new CommandLineException("A filename must be specified.");
+            }
+            if (!(format == null || "bdf".equals(format) || "pff2".equals(format))) {
+                throw new CommandLineException("Invalid format: must be `bdf' or `pff2'.");
+            }
+        } catch (CommandLineException e) {
+            System.err.println("Error: " + e.getMessage());
+            System.exit(1);
+        }
+
+        if (!new File(filename).exists()) {
+            System.err.println("Error: File `" + filename + "' not found.");
+            System.exit(1);
+        }
+
+        if (format == null) {
+            // Autodetect the format.
+            if (PFF2Loader.isPFF2File(filename))
+                format = "pff2";
+            else if (BDFLoader.isBDFFile(filename))
+                format = "bdf";
+            else {
+                System.err.println("Error: Unable to detect font file format " +
+                                   "for `" + filename + "'.");
+                System.exit(1);
+            }
+            if (verbose)
+                System.out.println("Detected file format `" + format + "'.");
+        }
+
+        Font font = null;
+        try {
+            if ("bdf".equals(format)) {
+                if (verbose)
+                    System.out.println("Loading BDF font.");
+                font = BDFLoader.loadFontFile(filename);
+            } else if ("pff2".equals(format)) {
+                if (verbose)
+                    System.out.println("Loading PFF2 font.");
+                font = PFF2Loader.loadFontFile(filename);
+            } else {
+                System.err.println("Error: Bad format `" + format + "'");
+                System.exit(1);
+            }
+        } catch (IOException e) {
+            System.err.println("I/O error loading font: " + e);
+            e.printStackTrace();
+            System.exit(1);
+        }
+
+        if (font == null) {
+            System.err.println("Error: Font not loaded.");
+            System.exit(1);
+        }
+
+        if (verbose) {
+            System.out.println("Loaded font: '" + font.getStandardName() + "'");
+        }
+
+        ViewerFrame f = new ViewerFrame(font);
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setLocationRelativeTo(null);   // Center the frame on screen.
+        f.setVisible(true);
+    }
+
+    private static class CommandLineException extends Exception {
+        public CommandLineException(String message) {
+            super(message);
+        }
+    }
+
+    private static void printUsageAndExit() {
+        System.err.println("GNU GRUB Font Viewer");
+        System.err.println();
+        System.err.println("Usage: Viewer [--format=FORMAT] FILE");
+        System.err.println("    --format=bdf   The font is in BDF format.");
+        System.err.println("    --format=pff2  The font is in PFF2 format.");
+        System.err.println("  If no --format option is given, the type will be");
+        System.err.println("  automatically detected.");
+        System.err.println();
+        System.exit(1);
+    }
+}

=== added file 'util/fonttool/src/org/gnu/grub/fonttool/ViewerFrame.java'
--- util/fonttool/src/org/gnu/grub/fonttool/ViewerFrame.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/src/org/gnu/grub/fonttool/ViewerFrame.java	2008-07-03 14:08:39 +0000
@@ -0,0 +1,61 @@
+package org.gnu.grub.fonttool;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.BevelBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+public class ViewerFrame extends JFrame {
+    private final Font font;
+
+    private JLabel startingCodePointLabel;
+    private JSlider startingCodePointSlider;
+    private CharMatrix charMatrix;
+    private CharView charView;
+    private JLabel statusBar;
+
+    public ViewerFrame(Font font) {
+        this.font = font;
+
+        createComponents();
+        buildUI();
+        setSize(800, 600);
+    }
+
+    private void createComponents() {
+        startingCodePointLabel = new JLabel("Starting Code Point");
+        startingCodePointSlider = new JSlider(JSlider.HORIZONTAL, 0, 65535, 0);
+        startingCodePointSlider.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent e) {
+                charMatrix.setStartingChar(startingCodePointSlider.getValue());
+            }
+        });
+        charMatrix = new CharMatrix();
+        charMatrix.setCharFont(font);
+        charMatrix.setGlyphSelectionListener(new CharMatrix.GlyphSelectionListener() {
+            public void glyphSelected(int codePoint) {
+                charView.setGlyph(font.getGlyph(codePoint));
+            }
+        });
+        charView = new CharView();
+        charView.setZoom(3);
+        charView.setBorder(new BevelBorder(BevelBorder.RAISED));
+        statusBar = new JLabel();
+    }
+
+    private void buildUI() {
+        JComponent topPanel = Box.createVerticalBox();
+        topPanel.add(startingCodePointLabel);
+        topPanel.add(startingCodePointSlider);
+
+        JComponent charPanel = new JPanel(new GridLayout(2, 1));
+        charPanel.add(charMatrix);
+        charPanel.add(charView);
+
+        setLayout(new BorderLayout());
+        add(topPanel, BorderLayout.NORTH);
+        add(charPanel, BorderLayout.CENTER);
+        add(statusBar, BorderLayout.SOUTH);
+    }
+}

=== added directory 'util/fonttool/test'
=== added directory 'util/fonttool/test/org'
=== added directory 'util/fonttool/test/org/gnu'
=== added directory 'util/fonttool/test/org/gnu/grub'
=== added directory 'util/fonttool/test/org/gnu/grub/fonttool'
=== added file 'util/fonttool/test/org/gnu/grub/fonttool/TestGlyph.java'
--- util/fonttool/test/org/gnu/grub/fonttool/TestGlyph.java	1970-01-01 00:00:00 +0000
+++ util/fonttool/test/org/gnu/grub/fonttool/TestGlyph.java	2008-07-03 14:10:25 +0000
@@ -0,0 +1,110 @@
+package org.gnu.grub.fonttool;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestGlyph {
+    @Test
+    public void testConstructor3x5() {
+        Glyph g = new Glyph(65, 3, 5, 0, 0, 0);
+
+        // Should be empty upon construction.
+        assertBitmapEquals("..." +
+                           "..." +
+                           "..." +
+                           "..." +
+                           "...",
+                           g.getBitmap());
+
+        // Should have ceil(3 * 5 / 8) = ceil(15 / 8) = ceil(1 + 7/8) = 2 bytes.
+        Assert.assertEquals("Wrong bitmap array size.",
+                            2, g.getBitmap().length);
+    }
+
+    @Test
+    public void testConstructor5x5() {
+        Glyph g = new Glyph(65, 5, 5, 0, 0, 0);
+
+        // Should be empty upon construction.
+        assertBitmapEquals("....." +
+                           "....." +
+                           "....." +
+                           "....." +
+                           ".....",
+                           g.getBitmap());
+
+        // Should have ceil(5 * 5 / 8) = ceil(25 / 8) = ceil(3 + 1/8) = 4 bytes.
+        Assert.assertEquals("Wrong bitmap array size.",
+                            4, g.getBitmap().length);
+    }
+
+    @Test
+    public void testSetPixel() {
+        Glyph g = new Glyph(65, 3, 5, 0, 0, 0);
+
+        g.setPixel(0, 0, true);
+        Assert.assertEquals(0x80, g.getBitmap()[0] & 0xFF);
+        Assert.assertEquals(0x00, g.getBitmap()[1] & 0xFF);
+        assertBitmapEquals("X.." +
+                           "..." +
+                           "..." +
+                           "..." +
+                           "...",
+                           g.getBitmap());
+
+        g.setPixel(2, 1, true);
+        Assert.assertEquals(0x84, g.getBitmap()[0] & 0xFF);
+        Assert.assertEquals(0x00, g.getBitmap()[1] & 0xFF);
+        assertBitmapEquals("X.." +
+                           "..X" +
+                           "..." +
+                           "..." +
+                           "...",
+                           g.getBitmap());
+    }
+
+    static void assertBitmapEquals(String expectedBitmap, byte[] actualBitmap) {
+        Assert.assertNotNull("expected bitmap null", expectedBitmap);
+        Assert.assertNotNull("actual bitmap null", actualBitmap);
+        StringBuilder errors = new StringBuilder();
+
+        int bit = 7;
+        int byteIndex = -1;
+        for (int bitIndex = 0; bitIndex < expectedBitmap.length(); bitIndex++) {
+            char c = expectedBitmap.charAt(bitIndex);
+            boolean expectedBit;
+            if (c == '.') {
+                expectedBit = false;
+            } else if (c == 'X') {
+                expectedBit = true;
+            } else {
+                throw new IllegalArgumentException("Bad character '" + c + "' in expected bitmap string");
+            }
+
+            byteIndex = bitIndex / 8;
+            byte b = actualBitmap[byteIndex];
+            boolean actualBit = (b & (1 << bit)) != 0;
+            if (actualBit != expectedBit) {
+                errors.append("[").append(bitIndex)
+                        .append("] wrong (it is ")
+                        .append(actualBit ? "1" : "0").append("). ");
+            }
+
+            if (bit == 0) {
+                bit = 7;
+            } else {
+                bit--;
+            }
+        }
+
+        if (byteIndex != expectedBitmap.length() / 8) {
+            errors.append("Last byte index wrong, was ")
+                    .append(byteIndex).append(" but expected ")
+                    .append(expectedBitmap.length() - 1);
+        }
+
+        if (errors.length() != 0) {
+            Assert.fail("Bitmap wrong: " + errors);
+        }
+    }
+}

=== modified file 'util/i386/pc/grub-mkrescue.in'
--- util/i386/pc/grub-mkrescue.in	2008-07-12 14:40:50 +0000
+++ util/i386/pc/grub-mkrescue.in	2008-07-19 21:39:24 +0000
@@ -71,7 +71,7 @@
     --modules=*)
 	modules=`echo "$option" | sed 's/--modules=//'` ;;
     --overlay=*)
-	overlay=`echo "$option" | sed 's/--overlay=//'` ;;
+	overlay=${overlay}${overlay:+ }`echo "$option" | sed 's/--overlay=//'` ;;
     --pkglibdir=*)
 	input_dir=`echo "$option" | sed 's/--pkglibdir=//'` ;;
     --grub-mkimage=*)
@@ -124,9 +124,10 @@
   echo "insmod $i"
 done > ${aux_dir}/boot/grub/grub.cfg
 
-if test "x$overlay" = x ; then : ; else
-  cp -dpR ${overlay}/* ${aux_dir}/
-fi
+for d in ${overlay}; do
+  echo "Overlaying $d"
+  cp -vdpR ${d}/* ${aux_dir}/
+done
 
 if [ "x${image_type}" = xfloppy -o "x${emulation}" = xfloppy ] ; then
   # build memdisk

=== modified file 'video/bitmap.c'
--- video/bitmap.c	2007-07-21 22:32:33 +0000
+++ video/bitmap.c	2008-07-03 13:49:18 +0000
@@ -78,7 +78,7 @@
 
   switch (blit_format)
     {
-      case GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8:
+      case GRUB_VIDEO_BLIT_FORMAT_RGBA_8888:
         mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB 
                                | GRUB_VIDEO_MODE_TYPE_ALPHA;
         mode_info->bpp = 32;
@@ -94,7 +94,7 @@
         mode_info->reserved_field_pos = 24;
         break;
 
-      case GRUB_VIDEO_BLIT_FORMAT_R8G8B8:
+      case GRUB_VIDEO_BLIT_FORMAT_RGB_888:
         mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
         mode_info->bpp = 24;
         mode_info->bytes_per_pixel = 3;

=== added file 'video/bitmap_scale.c'
--- video/bitmap_scale.c	1970-01-01 00:00:00 +0000
+++ video/bitmap_scale.c	2008-08-03 01:30:02 +0000
@@ -0,0 +1,101 @@
+/* bitmap_scale.c - Bitmap scaling interface. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/types.h>
+
+/* 
+ * This function creates a new scaled version of the bitmap SRC.  The new
+ * bitmap has dimensions DST_WIDTH by DST_HEIGHT.  The scaling algorithm
+ * is given by SCALE_METHOD.  If an error is encountered, the return code is
+ * not equal to GRUB_ERR_NONE, and the bitmap DST is either not created, or 
+ * it is destroyed before this function returns.
+ *
+ * Supports only direct color modes which have components separated
+ * into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). 
+ * But because of this simplifying assumption, the implementation is
+ * greatly simplified.
+ */
+grub_err_t
+grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
+                                 int dst_width, int dst_height,
+                                 struct grub_video_bitmap *src,
+                                 enum grub_video_bitmap_scale_method
+                                 scale_method)
+{
+  *dst = 0;
+
+  /* Verify the simplifying assumptions. */
+  if (src == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       "null src bitmap in grub_video_bitmap_create_scaled");
+  if (src->mode_info.red_field_pos % 8 != 0
+      || src->mode_info.green_field_pos % 8 != 0
+      || src->mode_info.blue_field_pos % 8 != 0
+      || src->mode_info.reserved_field_pos % 8 != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       "src format not supported for scale");
+  if (src->mode_info.width == 0 || src->mode_info.height == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
+  if (dst_width <= 0 || dst_height <= 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       "requested to scale to a size w/ a zero dimension");
+  if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       "bitmap to scale has inconsistent Bpp and bpp");
+
+  /* Create the new bitmap. */
+  grub_err_t ret;
+  ret = grub_video_bitmap_create (dst, dst_width, dst_height,
+                                  src->mode_info.blit_format);
+  if (ret != GRUB_ERR_NONE)
+    return ret;                 /* Error. */
+
+  switch (scale_method)
+    {
+    case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST:
+    case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST:
+      ret = grub_video_bitmap_scale_nn (*dst, src);
+      break;
+    case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST:
+    case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR:
+      ret = grub_video_bitmap_scale_bilinear (*dst, src);
+      break;
+    default:
+      ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale_method value");
+      break;
+    }
+
+  if (ret == GRUB_ERR_NONE)
+    {
+      /* Success:  *dst is now a pointer to the scaled bitmap. */
+      return GRUB_ERR_NONE;
+    }
+  else
+    {
+      /* Destroy the bitmap and return the error code. */
+      grub_video_bitmap_destroy (*dst);
+      *dst = 0;
+      return ret;
+    }
+}

=== added file 'video/bitmap_scale_bilinear.c'
--- video/bitmap_scale_bilinear.c	1970-01-01 00:00:00 +0000
+++ video/bitmap_scale_bilinear.c	2008-07-03 14:28:15 +0000
@@ -0,0 +1,145 @@
+/* bitmap_scale_bilinear.c - Bilinear image scaling algorithm. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/types.h>
+
+/* 
+ * Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the 
+ * dimensions of DST.  This function uses the bilinear interpolation algorithm
+ * to interpolate the pixels.
+ *
+ * Supports only direct color modes which have components separated
+ * into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). 
+ * But because of this simplifying assumption, the implementation is
+ * greatly simplified.
+ */
+grub_err_t
+grub_video_bitmap_scale_bilinear (struct grub_video_bitmap *dst,
+                                  struct grub_video_bitmap *src)
+{
+  /* Verify the simplifying assumptions. */
+  if (dst == 0 || src == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale func");
+  if (dst->mode_info.red_field_pos % 8 != 0
+      || dst->mode_info.green_field_pos % 8 != 0
+      || dst->mode_info.blue_field_pos % 8 != 0
+      || dst->mode_info.reserved_field_pos % 8 != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported");
+  if (src->mode_info.red_field_pos % 8 != 0
+      || src->mode_info.green_field_pos % 8 != 0
+      || src->mode_info.blue_field_pos % 8 != 0
+      || src->mode_info.reserved_field_pos % 8 != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported");
+  if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
+      || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
+      || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
+      || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
+      || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
+      || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
+      || dst->mode_info.reserved_field_pos !=
+      src->mode_info.reserved_field_pos
+      || dst->mode_info.reserved_mask_size !=
+      src->mode_info.reserved_mask_size)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
+  if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
+  if (dst->mode_info.width == 0 || dst->mode_info.height == 0
+      || src->mode_info.width == 0 || src->mode_info.height == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
+
+  grub_uint8_t *ddata = dst->data;
+  grub_uint8_t *sdata = src->data;
+  int dw = dst->mode_info.width;
+  int dh = dst->mode_info.height;
+  int sw = src->mode_info.width;
+  int sh = src->mode_info.height;
+  int dstride = dst->mode_info.pitch;
+  int sstride = src->mode_info.pitch;
+  /* bytes_per_pixel is the same for both src and dst. */
+  int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
+
+  int dy;
+  for (dy = 0; dy < dh; dy++)
+    {
+      int dx;
+      for (dx = 0; dx < dw; dx++)
+        {
+          grub_uint8_t *dptr;
+          grub_uint8_t *sptr;
+          int sx;
+          int sy;
+          int comp;
+
+          /* Compute the source coordinate that the destination coordinate
+           * maps to.  Note: sx/sw = dx/dw  =>  sx = sw*dx/dw. */
+          sx = sw * dx / dw;
+          sy = sh * dy / dh;
+
+          /* Get the address of the pixels in src and dst. */
+          dptr = ddata + dy * dstride + dx * bytes_per_pixel;
+          sptr = sdata + sy * sstride + sx * bytes_per_pixel;
+
+          /* If we have enough space to do so, use bilinear interpolation.
+           * Otherwise, fall back to nearest neighbor for this pixel. */
+          if (sx < sw - 1 && sy < sh - 1)
+            {
+              /* Do bilinear interpolation. */
+
+              /* Fixed-point .8 numbers representing the fraction of the
+               * distance in the x (u) and y (v) direction within the 
+               * box of 4 pixels in the source. */
+              int u = (256 * sw * dx / dw) - (sx * 256);
+              int v = (256 * sh * dy / dh) - (sy * 256);
+
+              for (comp = 0; comp < bytes_per_pixel; comp++)
+                {
+                  /* Get the component's values for the 
+                   * 4 source corner pixels. */
+                  grub_uint8_t f00 = sptr[comp];
+                  grub_uint8_t f10 = sptr[comp + bytes_per_pixel];
+                  grub_uint8_t f01 = sptr[comp + sstride];
+                  grub_uint8_t f11 = sptr[comp + sstride + bytes_per_pixel];
+
+                  /* Do linear interpolations along the top and bottom
+                   * rows of the box. */
+                  grub_uint8_t f0y = (256 - v) * f00 / 256 + v * f01 / 256;
+                  grub_uint8_t f1y = (256 - v) * f10 / 256 + v * f11 / 256;
+
+                  /* Interpolate vertically. */
+                  grub_uint8_t fxy = (256 - u) * f0y / 256 + u * f1y / 256;
+
+                  dptr[comp] = fxy;
+                }
+            }
+          else
+            {
+              /* Fall back to nearest neighbor interpolation. */
+              /* Copy the pixel color value. */
+              for (comp = 0; comp < bytes_per_pixel; comp++)
+                dptr[comp] = sptr[comp];
+            }
+        }
+    }
+  return GRUB_ERR_NONE;
+}

=== added file 'video/bitmap_scale_nn.c'
--- video/bitmap_scale_nn.c	1970-01-01 00:00:00 +0000
+++ video/bitmap_scale_nn.c	2008-07-03 14:27:43 +0000
@@ -0,0 +1,109 @@
+/* bitmap_scale_nn.c - Nearest neighbor image scaling algorithm. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/video.h>
+#include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
+#include <grub/types.h>
+
+/* 
+ * Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the 
+ * dimensions of DST.  This function uses the nearest neighbor algorithm to
+ * interpolate the pixels.
+ *
+ * Supports only direct color modes which have components separated
+ * into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). 
+ * But because of this simplifying assumption, the implementation is
+ * greatly simplified.
+ */
+grub_err_t
+grub_video_bitmap_scale_nn (struct grub_video_bitmap *dst,
+                            struct grub_video_bitmap *src)
+{
+  /* Verify the simplifying assumptions. */
+  if (dst == 0 || src == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale_nn");
+  if (dst->mode_info.red_field_pos % 8 != 0
+      || dst->mode_info.green_field_pos % 8 != 0
+      || dst->mode_info.blue_field_pos % 8 != 0
+      || dst->mode_info.reserved_field_pos % 8 != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported");
+  if (src->mode_info.red_field_pos % 8 != 0
+      || src->mode_info.green_field_pos % 8 != 0
+      || src->mode_info.blue_field_pos % 8 != 0
+      || src->mode_info.reserved_field_pos % 8 != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported");
+  if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
+      || dst->mode_info.red_mask_size != src->mode_info.red_mask_size
+      || dst->mode_info.green_field_pos != src->mode_info.green_field_pos
+      || dst->mode_info.green_mask_size != src->mode_info.green_mask_size
+      || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
+      || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
+      || dst->mode_info.reserved_field_pos !=
+      src->mode_info.reserved_field_pos
+      || dst->mode_info.reserved_mask_size !=
+      src->mode_info.reserved_mask_size)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
+  if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible");
+  if (dst->mode_info.width == 0 || dst->mode_info.height == 0
+      || src->mode_info.width == 0 || src->mode_info.height == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension");
+
+  grub_uint8_t *ddata = dst->data;
+  grub_uint8_t *sdata = src->data;
+  int dw = dst->mode_info.width;
+  int dh = dst->mode_info.height;
+  int sw = src->mode_info.width;
+  int sh = src->mode_info.height;
+  int dstride = dst->mode_info.pitch;
+  int sstride = src->mode_info.pitch;
+  /* bytes_per_pixel is the same for both src and dst. */
+  int bytes_per_pixel = dst->mode_info.bytes_per_pixel;
+
+  int dy;
+  for (dy = 0; dy < dh; dy++)
+    {
+      int dx;
+      for (dx = 0; dx < dw; dx++)
+        {
+          grub_uint8_t *dptr;
+          grub_uint8_t *sptr;
+          int sx;
+          int sy;
+          int comp;
+
+          /* Compute the source coordinate that the destination coordinate
+           * maps to.  Note: sx/sw = dx/dw  =>  sx = sw*dx/dw. */
+          sx = sw * dx / dw;
+          sy = sh * dy / dh;
+
+          /* Get the address of the pixels in src and dst. */
+          dptr = ddata + dy * dstride + dx * bytes_per_pixel;
+          sptr = sdata + sy * sstride + sx * bytes_per_pixel;
+
+          /* Copy the pixel color value. */
+          for (comp = 0; comp < bytes_per_pixel; comp++)
+            dptr[comp] = sptr[comp];
+        }
+    }
+  return GRUB_ERR_NONE;
+}

=== modified file 'video/i386/pc/vbe.c'
--- video/i386/pc/vbe.c	2008-01-21 15:48:27 +0000
+++ video/i386/pc/vbe.c	2008-07-19 19:42:37 +0000
@@ -63,6 +63,7 @@
 static struct
 {
   struct grub_video_render_target render_target;
+  int is_double_buffered;       /* Is the video mode double buffered? */
 
   unsigned int bytes_per_scan_line;
   unsigned int bytes_per_pixel;
@@ -77,6 +78,24 @@
 static grub_uint32_t mode_in_use = 0x55aa;
 static grub_uint16_t *mode_list;
 
+static struct 
+{
+  grub_size_t page_size;        /* The size of a page in bytes. */
+
+  /* For page flipping strategy. */
+  int displayed_page;           /* The page # that is the front buffer. */
+  int render_page;              /* The page # that is the back buffer. */
+
+  /* For blit strategy. */
+  grub_uint8_t *offscreen_buffer;
+
+  /* Virtual functions. */
+  int (*update_screen) (void);
+  int (*destroy) (void);
+} doublebuf_state;
+
+static void double_buffering_init (void);
+
 static void *
 real2pm (grub_vbe_farptr_t ptr)
 {
@@ -376,6 +395,7 @@
   /* Reset frame buffer and render target variables.  */
   grub_memset (&framebuffer, 0, sizeof(framebuffer));
   render_target = &framebuffer.render_target;
+  grub_memset (&doublebuf_state, 0, sizeof(doublebuf_state));
 
   return GRUB_ERR_NONE;
 }
@@ -391,6 +411,9 @@
     /* TODO: Decide, is this something we want to do.  */
     return grub_errno;
 
+  if (doublebuf_state.destroy)
+    doublebuf_state.destroy();
+
   /* TODO: Free any resources allocated by driver.  */
   grub_free (mode_list);
   mode_list = 0;
@@ -533,9 +556,13 @@
       render_target->viewport.width = active_mode_info.x_resolution;
       render_target->viewport.height = active_mode_info.y_resolution;
 
-      /* Set framebuffer pointer and mark it as non allocated.  */
+      /* Mark framebuffer memory as non allocated.  */
       render_target->is_allocated = 0;
-      render_target->data = framebuffer.ptr;
+
+      /* Set up double buffering information. */
+      framebuffer.is_double_buffered =
+        ((mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) != 0);
+      double_buffering_init ();
 
       /* Copy default palette to initialize emulated palette.  */
       for (i = 0; 
@@ -556,6 +583,166 @@
   return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found.");
 }
 
+/* 
+   Set framebuffer render target page and display the proper page, based on
+   `doublebuf_state.render_page' and `doublebuf_state.displayed_page',
+   respectively. 
+
+   Returns 0 upon success, nonzero upon failure.
+ */
+static int
+doublebuf_pageflipping_commit (void)
+{
+  /* Set the render target's data pointer to the start of the render_page. */
+  framebuffer.render_target.data =
+    ((char *) framebuffer.ptr) +
+    doublebuf_state.page_size * doublebuf_state.render_page;
+
+  /* Tell the video adapter to display the new front page. */
+  int display_start_line =
+    framebuffer.render_target.mode_info.height 
+    * doublebuf_state.displayed_page;
+ 
+  grub_vbe_status_t vbe_err = 
+    grub_vbe_bios_set_display_start (0, display_start_line);
+  if (vbe_err != GRUB_VBE_STATUS_OK)
+    return 1;
+
+  return 0;
+}
+
+static int
+doublebuf_pageflipping_update_screen (void)
+{
+  /* Swap the page numbers in the framebuffer struct. */
+  int new_displayed_page = doublebuf_state.render_page;
+  doublebuf_state.render_page = doublebuf_state.displayed_page;
+  doublebuf_state.displayed_page = new_displayed_page;
+
+  return doublebuf_pageflipping_commit ();
+}
+
+static int
+doublebuf_pageflipping_destroy (void)
+{
+  doublebuf_state.update_screen = 0;
+  doublebuf_state.destroy = 0;
+  return 0;
+}
+
+static int
+doublebuf_pageflipping_init (void)
+{
+  doublebuf_state.page_size =
+    framebuffer.bytes_per_scan_line * render_target->mode_info.height;
+  
+  /* Get video RAM size in bytes.  */
+  grub_size_t vram_size = controller_info.total_memory << 16;
+
+  if (2 * doublebuf_state.page_size > vram_size)
+    return 1;   /* Not enough video memory for 2 pages. */
+
+  doublebuf_state.displayed_page = 0;
+  doublebuf_state.render_page = 1;
+
+  doublebuf_state.update_screen = doublebuf_pageflipping_update_screen;
+  doublebuf_state.destroy = doublebuf_pageflipping_destroy;
+
+  /* Set the framebuffer memory data pointer and display the right page. */
+  if (doublebuf_pageflipping_commit () != GRUB_ERR_NONE)
+    return 1;   /* Unable to set the display start.  */
+
+  framebuffer.render_target.mode_info.mode_type
+    |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  return 0;
+}
+
+static int
+doublebuf_blit_update_screen (void)
+{
+  grub_memcpy (framebuffer.ptr,
+               doublebuf_state.offscreen_buffer, 
+               doublebuf_state.page_size);
+  return 0;
+}
+
+static int
+doublebuf_blit_destroy (void)
+{
+  grub_free (doublebuf_state.offscreen_buffer);
+  doublebuf_state.offscreen_buffer = 0;
+
+  doublebuf_state.update_screen = 0;
+  doublebuf_state.destroy = 0;
+  return 0;
+}
+
+static int
+doublebuf_blit_init (void)
+{
+  doublebuf_state.page_size =
+    framebuffer.bytes_per_scan_line * render_target->mode_info.height;
+
+  doublebuf_state.offscreen_buffer = (grub_uint8_t *)
+    grub_malloc (doublebuf_state.page_size);
+  if (doublebuf_state.offscreen_buffer == 0)
+    return 1;   /* Error.  */
+
+  framebuffer.render_target.data = doublebuf_state.offscreen_buffer;
+  doublebuf_state.update_screen = doublebuf_blit_update_screen;
+  doublebuf_state.destroy = doublebuf_blit_destroy;
+
+  framebuffer.render_target.mode_info.mode_type
+    |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  return 0;
+}
+
+static int
+doublebuf_null_update_screen (void)
+{
+  return 0;
+}
+
+static int
+doublebuf_null_destroy (void)
+{
+  doublebuf_state.update_screen = 0;
+  doublebuf_state.destroy = 0;
+  return 0;
+}
+
+static int
+doublebuf_null_init (void)
+{
+  framebuffer.render_target.data = framebuffer.ptr;
+  doublebuf_state.update_screen = doublebuf_null_update_screen;
+  doublebuf_state.destroy = doublebuf_null_destroy;
+
+  framebuffer.render_target.mode_info.mode_type
+    &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED;
+  return 0;
+}
+
+/* Select the best double buffering mode available.  */
+static void
+double_buffering_init (void)
+{
+  if (doublebuf_state.destroy)
+    doublebuf_state.destroy();
+
+  if (framebuffer.is_double_buffered)
+    {
+      if (doublebuf_pageflipping_init () == 0)
+        return;
+
+      if (doublebuf_blit_init () == 0)
+        return;
+    }
+
+  /* Fall back to no double buffering. */
+  doublebuf_null_init ();
+}
+
 static grub_err_t
 grub_video_vbe_get_info (struct grub_video_mode_info *mode_info)
 {
@@ -708,6 +895,16 @@
 
       return minindex;
     }
+  else if ((render_target->mode_info.mode_type 
+            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+    {
+       if (red == render_target->mode_info.fg_red
+           && green == render_target->mode_info.fg_green
+           && blue == render_target->mode_info.fg_blue)
+         return 1;
+       else
+         return 0;
+    }
   else
     {
       grub_uint32_t value;
@@ -737,6 +934,17 @@
     /* No alpha available in index color modes, just use
        same value as in only RGB modes.  */
     return grub_video_vbe_map_rgb (red, green, blue);
+  else if ((render_target->mode_info.mode_type 
+            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+    {
+      if (red == render_target->mode_info.fg_red
+          && green == render_target->mode_info.fg_green
+          && blue == render_target->mode_info.fg_blue
+          && alpha == render_target->mode_info.fg_alpha)
+        return 1;
+      else
+        return 0;
+    }
   else
     {
       grub_uint32_t value;
@@ -797,6 +1005,24 @@
       *alpha = framebuffer.palette[color].a;
       return;
     }
+  else if ((mode_info->mode_type
+            & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) != 0)
+    {
+      if (color & 1)
+        {
+          *red = mode_info->fg_red;
+          *green = mode_info->fg_green;
+          *blue = mode_info->fg_blue;
+          *alpha = mode_info->fg_alpha;
+        }
+      else
+        {
+          *red = mode_info->bg_red;
+          *green = mode_info->bg_green;
+          *blue = mode_info->bg_blue;
+          *alpha = mode_info->bg_alpha;
+        }
+    }
   else
     {
       grub_uint32_t tmp;
@@ -876,17 +1102,24 @@
   target.data = render_target->data;
 
   /* Try to figure out more optimized version.  */
-  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
-    {
-      grub_video_i386_vbefill_R8G8B8A8 (&target, color, x, y, 
-                                        width, height);
-      return GRUB_ERR_NONE;
-    }
-
-  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
-    {
-      grub_video_i386_vbefill_R8G8B8 (&target, color, x, y,
-                                      width, height);
+  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+    {
+      grub_video_i386_vbefill_direct32 (&target, color, x, y, 
+                                        width, height);
+      return GRUB_ERR_NONE;
+    }
+
+  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
+    {
+      grub_video_i386_vbefill_direct32 (&target, color, x, y, 
+                                        width, height);
+      return GRUB_ERR_NONE;
+    }
+
+  if (target.mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+    {
+      grub_video_i386_vbefill_direct24 (&target, color, x, y,
+                                        width, height);
       return GRUB_ERR_NONE;
     }
 
@@ -903,76 +1136,6 @@
   return GRUB_ERR_NONE;
 }
 
-// TODO: Remove this method and replace with bitmap based glyphs
-static grub_err_t
-grub_video_vbe_blit_glyph (struct grub_font_glyph * glyph,
-                           grub_video_color_t color, int x, int y)
-{
-  struct grub_video_i386_vbeblit_info target;
-  unsigned int width;
-  unsigned int charwidth;
-  unsigned int height;
-  unsigned int i;
-  unsigned int j;
-  unsigned int x_offset = 0;
-  unsigned int y_offset = 0;
-
-  /* Make sure there is something to do.  */
-  if (x >= (int)render_target->viewport.width)
-    return GRUB_ERR_NONE;
-
-  if (y >= (int)render_target->viewport.height)
-    return GRUB_ERR_NONE;
-
-  /* Calculate glyph dimensions.  */
-  width = ((glyph->width + 7) / 8) * 8;
-  charwidth = width;
-  height = glyph->height;
-
-  if (x + (int)width < 0)
-    return GRUB_ERR_NONE;
-
-  if (y + (int)height < 0)
-    return GRUB_ERR_NONE;
-
-  /* Do not allow drawing out of viewport.  */
-  if (x < 0)
-    {
-      width += x;
-      x_offset = (unsigned int)-x;
-      x = 0;
-    }
-  if (y < 0)
-    {
-      height += y;
-      y_offset = (unsigned int)-y;
-      y = 0;
-    }
-
-  if ((x + width) > render_target->viewport.width)
-    width = render_target->viewport.width - x;
-  if ((y + height) > render_target->viewport.height)
-    height = render_target->viewport.height - y;
-
-  /* Add viewport offset.  */
-  x += render_target->viewport.x;
-  y += render_target->viewport.y;
-
-  /* Use vbeblit_info to encapsulate rendering.  */
-  target.mode_info = &render_target->mode_info;
-  target.data = render_target->data;
-
-  /* Draw glyph.  */
-  for (j = 0; j < height; j++)
-    for (i = 0; i < width; i++)
-      if ((glyph->bitmap[((i + x_offset) / 8) 
-                         + (j + y_offset) * (charwidth / 8)] 
-           & (1 << ((charwidth - (i + x_offset) - 1) % 8))))
-        set_pixel (&target, x+i, y+j, color);
-
-  return GRUB_ERR_NONE;
-}
-
 /* NOTE: This function assumes that given coordinates are within bounds of 
    handled data.  */
 static void
@@ -985,19 +1148,35 @@
   if (oper == GRUB_VIDEO_BLIT_REPLACE)
     {
       /* Try to figure out more optimized version for replace operator.  */
-      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
         {
-          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
-            {
-              grub_video_i386_vbeblit_R8G8B8X8_R8G8B8X8 (target, source,
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
+            {
+              grub_video_i386_vbeblit_direct32_copy (target, source,
+                                                     x, y, width, height,
+                                                     offset_x, offset_y);
+              return;
+            }
+
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+            {
+              grub_video_i386_vbeblit_BGRX8888_RGBX8888 (target, source,
                                                          x, y, width, height,
                                                          offset_x, offset_y);
               return;
             }
 
-          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
-            {
-              grub_video_i386_vbeblit_R8G8B8_R8G8B8X8 (target, source,
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
+            {
+              grub_video_i386_vbeblit_BGR888_RGBX8888 (target, source,
+                                                       x, y, width, height,
+                                                       offset_x, offset_y);
+              return;
+            }
+
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+            {
+              grub_video_i386_vbeblit_RGB888_RGBX8888 (target, source,
                                                        x, y, width, height,
                                                        offset_x, offset_y);
               return;
@@ -1005,26 +1184,42 @@
 
           if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
             {
-              grub_video_i386_vbeblit_index_R8G8B8X8 (target, source,
+              grub_video_i386_vbeblit_index_RGBX8888 (target, source,
                                                       x, y, width, height,
                                                       offset_x, offset_y);
               return;
             }
         }
 
-      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
         {
-          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
-            {
-              grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (target, source,
-                                                       x, y, width, height,
-                                                       offset_x, offset_y);
-              return;
-            }
-
-          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
-            {
-              grub_video_i386_vbeblit_R8G8B8_R8G8B8 (target, source,
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+            {
+              grub_video_i386_vbeblit_BGRA8888_RGB888 (target, source,
+                                                       x, y, width, height,
+                                                       offset_x, offset_y);
+              return;
+            }
+
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
+            {
+              grub_video_i386_vbeblit_RGBA8888_RGB888 (target, source,
+                                                       x, y, width, height,
+                                                       offset_x, offset_y);
+              return;
+            }
+
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
+            {
+              grub_video_i386_vbeblit_BGR888_RGB888 (target, source,
+                                                     x, y, width, height,
+                                                     offset_x, offset_y);
+              return;
+            }
+
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+            {
+              grub_video_i386_vbeblit_RGB888_RGB888 (target, source,
                                                      x, y, width, height,
                                                      offset_x, offset_y);
               return;
@@ -1032,13 +1227,24 @@
 
           if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
             {
-              grub_video_i386_vbeblit_index_R8G8B8 (target, source,
+              grub_video_i386_vbeblit_index_RGB888 (target, source,
                                                     x, y, width, height,
                                                     offset_x, offset_y);
               return;
             }
         }
 
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+        {
+          if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+            {
+              grub_video_i386_vbeblit_direct32_copy (target, source,
+                                                     x, y, width, height,
+                                                     offset_x, offset_y);
+              return;
+            }
+        }
+
       if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
         {
           if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
@@ -1057,19 +1263,35 @@
   else
     {
       /* Try to figure out more optimized blend operator.  */
-      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
       {
-        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
-        {
-          grub_video_i386_vbeblit_R8G8B8A8_R8G8B8A8 (target, source,
-              x, y, width, height,
-              offset_x, offset_y);
-          return;
-        }
-
-        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
-        {
-          grub_video_i386_vbeblit_R8G8B8_R8G8B8A8 (target, source,
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+        {
+          grub_video_i386_vbeblit_BGRA8888_RGBA8888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
+        {
+          grub_video_i386_vbeblit_RGBA8888_RGBA8888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
+        {
+          grub_video_i386_vbeblit_BGR888_RGBA8888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+        {
+          grub_video_i386_vbeblit_RGB888_RGBA8888 (target, source,
               x, y, width, height,
               offset_x, offset_y);
           return;
@@ -1077,26 +1299,42 @@
 
         if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
         {
-          grub_video_i386_vbeblit_index_R8G8B8A8 (target, source,
+          grub_video_i386_vbeblit_index_RGBA8888 (target, source,
               x, y, width, height,
               offset_x, offset_y);
           return;
         }
       }
 
-      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
       {
-        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8)
-        {
-          grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (target, source,
-              x, y, width, height,
-              offset_x, offset_y);
-          return;
-        }
-
-        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_R8G8B8)
-        {
-          grub_video_i386_vbeblit_R8G8B8_R8G8B8 (target, source,
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888)
+        {
+          grub_video_i386_vbeblit_BGRA8888_RGB888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888)
+        {
+          grub_video_i386_vbeblit_RGBA8888_RGB888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888)
+        {
+          grub_video_i386_vbeblit_BGR888_RGB888 (target, source,
+              x, y, width, height,
+              offset_x, offset_y);
+          return;
+        }
+
+        if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_RGB_888)
+        {
+          grub_video_i386_vbeblit_RGB888_RGB888 (target, source,
               x, y, width, height,
               offset_x, offset_y);
           return;
@@ -1104,7 +1342,7 @@
 
         if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR)
         {
-          grub_video_i386_vbeblit_index_R8G8B8 (target, source,
+          grub_video_i386_vbeblit_index_RGB888 (target, source,
               x, y, width, height,
               offset_x, offset_y);
           return;
@@ -1219,6 +1457,77 @@
   return GRUB_ERR_NONE;
 }
 
+/* 
+ * Draw the specified glyph at (x, y).  The y coordinate designates the
+ * baseline of the character, while the x coordinate designates the left
+ * side location of the character. 
+ */
+static grub_err_t
+grub_video_vbe_blit_glyph (struct grub_font_glyph *glyph,
+                           grub_video_color_t color, 
+                           int left_x, int baseline_y)
+{
+  struct grub_video_bitmap glyph_bitmap;
+
+  /* Don't try to draw empty glyphs (U+0020, etc.). */
+  if (glyph->width == 0 || glyph->height == 0)
+    return GRUB_ERR_NONE;
+
+  glyph_bitmap.mode_info.width = glyph->width;
+  glyph_bitmap.mode_info.height = glyph->height;
+  glyph_bitmap.mode_info.mode_type = 
+    (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
+    | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP;
+  glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED;
+  glyph_bitmap.mode_info.bpp = 1;
+  glyph_bitmap.mode_info.bytes_per_pixel = 0;  /* Really 1 bit per pixel. */
+  glyph_bitmap.mode_info.pitch = glyph->width; /* Packed densely as bits. */
+  glyph_bitmap.mode_info.number_of_colors = 2;
+  glyph_bitmap.mode_info.bg_red = 0;
+  glyph_bitmap.mode_info.bg_green = 0;
+  glyph_bitmap.mode_info.bg_blue = 0;
+  glyph_bitmap.mode_info.bg_alpha = 0;
+  grub_video_vbe_unmap_color(color, 
+                             &glyph_bitmap.mode_info.fg_red,
+                             &glyph_bitmap.mode_info.fg_green,
+                             &glyph_bitmap.mode_info.fg_blue,
+                             &glyph_bitmap.mode_info.fg_alpha);
+  glyph_bitmap.data = glyph->bitmap;
+
+  int bitmap_left = left_x + glyph->offset_x;
+  int bitmap_bottom = baseline_y - glyph->offset_y;
+  int bitmap_top = bitmap_bottom - glyph->height;
+
+  return grub_video_vbe_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND,
+                                     bitmap_left, bitmap_top,
+                                     0, 0,
+                                     glyph->width, glyph->height);
+}
+
+static grub_err_t
+grub_video_vbe_draw_string (const char *str, grub_font_t font, 
+                            grub_video_color_t color, 
+                            int left_x, int baseline_y)
+{
+  grub_size_t len;
+  grub_size_t i;
+  int x;
+  struct grub_font_glyph *glyph;
+
+  len = grub_strlen (str);
+  x = left_x;
+  for (i = 0; i < len; i++)
+    {
+      glyph = grub_font_get_glyph (font, str[i]);
+      if (grub_video_vbe_blit_glyph (glyph, color, x, baseline_y) 
+          != GRUB_ERR_NONE)
+        return grub_errno;
+      x += glyph->device_width;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
 static grub_err_t
 grub_video_vbe_blit_render_target (struct grub_video_render_target *source,
                                    enum grub_video_blit_operators oper,
@@ -1403,10 +1712,13 @@
   return GRUB_ERR_NONE;
 }
 
-static grub_err_t 
+static grub_err_t
 grub_video_vbe_swap_buffers (void)
 {
-  /* TODO: Implement buffer swapping.  */
+  if (doublebuf_state.update_screen () != 0)
+    return grub_error (GRUB_ERR_INVALID_COMMAND,
+                       "Double buffer update failed");
+
   return GRUB_ERR_NONE;
 }
 
@@ -1505,17 +1817,13 @@
 static grub_err_t
 grub_video_vbe_set_active_render_target (struct grub_video_render_target *target)
 {
-  if (target == GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER)
+  if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY)
     {
       render_target = &framebuffer.render_target;
-
+      
       return GRUB_ERR_NONE;
     }
 
-  if (target == GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER)
-    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, 
-                       "double buffering not implemented yet.");
-
   if (! target->data)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, 
                        "invalid render target given.");
@@ -1551,6 +1859,7 @@
     .unmap_color = grub_video_vbe_unmap_color,
     .fill_rect = grub_video_vbe_fill_rect,
     .blit_glyph = grub_video_vbe_blit_glyph,
+    .draw_string = grub_video_vbe_draw_string,
     .blit_bitmap = grub_video_vbe_blit_bitmap,
     .blit_render_target = grub_video_vbe_blit_render_target,
     .scroll = grub_video_vbe_scroll,

=== modified file 'video/i386/pc/vbeblit.c'
--- video/i386/pc/vbeblit.c	2008-01-01 12:02:07 +0000
+++ video/i386/pc/vbeblit.c	2008-07-09 17:27:53 +0000
@@ -35,7 +35,343 @@
 #include <grub/video.h>
 
 void
-grub_video_i386_vbeblit_R8G8B8A8_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_BGRX8888_RGBX8888 (struct grub_video_i386_vbeblit_info
+                                           *dst,
+                                           struct grub_video_i386_vbeblit_info
+                                           *src, int x, int y, int width,
+                                           int height, int offset_x,
+                                           int offset_y)
+{
+  int i;
+  int j;
+  grub_uint8_t *srcptr;
+  grub_uint8_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint8_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint8_t *) get_data_ptr (dst, x, y);
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint8_t r = *srcptr++;
+          grub_uint8_t g = *srcptr++;
+          grub_uint8_t b = *srcptr++;
+          grub_uint8_t a = *srcptr++;
+
+          *dstptr++ = b;
+          *dstptr++ = g;
+          *dstptr++ = r;
+          *dstptr++ = a;
+        }
+      srcptr += srcrowskip;
+      dstptr += dstrowskip;
+    }
+}
+
+void
+grub_video_i386_vbeblit_BGRA8888_RGB888 (struct grub_video_i386_vbeblit_info
+                                         *dst,
+                                         struct grub_video_i386_vbeblit_info
+                                         *src, int x, int y, int width,
+                                         int height, int offset_x,
+                                         int offset_y)
+{
+  int i;
+  int j;
+  grub_uint8_t *srcptr;
+  grub_uint8_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint8_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint8_t *) get_data_ptr (dst, x, y);
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint8_t r = *srcptr++;
+          grub_uint8_t g = *srcptr++;
+          grub_uint8_t b = *srcptr++;
+
+          *dstptr++ = b;
+          *dstptr++ = g;
+          *dstptr++ = r;
+          *dstptr++ = 255;      /* Alpha component: Set opaque. */
+        }
+      srcptr += srcrowskip;
+      dstptr += dstrowskip;
+    }
+}
+
+void
+grub_video_i386_vbeblit_BGR888_RGB888 (struct grub_video_i386_vbeblit_info
+                                         *dst,
+                                         struct grub_video_i386_vbeblit_info
+                                         *src, int x, int y, int width,
+                                         int height, int offset_x,
+                                         int offset_y)
+{
+  int i;
+  int j;
+  grub_uint8_t *srcptr;
+  grub_uint8_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint8_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint8_t *) get_data_ptr (dst, x, y);
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint8_t r = *srcptr++;
+          grub_uint8_t g = *srcptr++;
+          grub_uint8_t b = *srcptr++;
+
+          *dstptr++ = b;
+          *dstptr++ = g;
+          *dstptr++ = r;
+        }
+      srcptr += srcrowskip;
+      dstptr += dstrowskip;
+    }
+}
+
+void
+grub_video_i386_vbeblit_BGRA8888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                           struct grub_video_i386_vbeblit_info *src,
+                                           int x, int y, int width, int height,
+                                           int offset_x, int offset_y)
+{
+  grub_uint32_t *srcptr;
+  grub_uint32_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+  int i;
+  int j;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint32_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint32_t *) get_data_ptr (dst, x, y);
+
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint32_t color;
+          unsigned int sr;
+          unsigned int sg;
+          unsigned int sb;
+          unsigned int a;
+          unsigned int dr;
+          unsigned int dg;
+          unsigned int db;
+
+          color = *srcptr++;
+
+          a = color >> 24;
+
+          if (a == 0)
+            {
+              /* Skip transparent source pixels.  */
+              dstptr++;
+              continue;
+            }
+
+          sr = (color >> 0) & 0xFF;
+          sg = (color >> 8) & 0xFF;
+          sb = (color >> 16) & 0xFF;
+
+          if (a == 255)
+            {
+              /* Opaque pixel shortcut.  */
+              dr = sr;
+              dg = sg;
+              db = sb;
+            }
+          else
+            {
+              /* General pixel color blending.  */
+              color = *dstptr;
+
+              dr = (color >> 16) & 0xFF;
+              dr = (dr * (255 - a) + sr * a) / 255;
+              dg = (color >> 8) & 0xFF;
+              dg = (dg * (255 - a) + sg * a) / 255;
+              db = (color >> 0) & 0xFF;
+              db = (db * (255 - a) + sb * a) / 255;
+            }
+
+          color = (a << 24) | (dr << 16) | (dg << 8) | db;
+
+          *dstptr++ = color;
+        }
+
+      srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip);
+      dstptr = (grub_uint32_t *) (((grub_uint8_t *) dstptr) + dstrowskip);
+    }
+}
+
+void
+grub_video_i386_vbeblit_BGR888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
+                                          struct grub_video_i386_vbeblit_info *src,
+                                          int x, int y, int width, int height,
+                                          int offset_x, int offset_y)
+{
+  grub_uint32_t *srcptr;
+  grub_uint8_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+  int i;
+  int j;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint32_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint8_t *) get_data_ptr (dst, x, y);
+
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint32_t color;
+          unsigned int sr;
+          unsigned int sg;
+          unsigned int sb;
+          unsigned int a;
+          unsigned int dr;
+          unsigned int dg;
+          unsigned int db;
+
+          color = *srcptr++;
+
+          a = color >> 24;
+
+          if (a == 0)
+            {
+              /* Skip transparent source pixels.  */
+              dstptr += 3;
+              continue;
+            }
+
+          sr = (color >> 0) & 0xFF;
+          sg = (color >> 8) & 0xFF;
+          sb = (color >> 16) & 0xFF;
+
+          if (a == 255)
+            {
+              /* Opaque pixel shortcut.  */
+              dr = sr;
+              dg = sg;
+              db = sb;
+            }
+          else
+            {
+              /* General pixel color blending.  */
+              color = *dstptr;
+
+              db = dstptr[0];
+              db = (db * (255 - a) + sb * a) / 255;
+              dg = dstptr[1];
+              dg = (dg * (255 - a) + sg * a) / 255;
+              dr = dstptr[2];
+              dr = (dr * (255 - a) + sr * a) / 255;
+            }
+
+          *dstptr++ = db;
+          *dstptr++ = dg;
+          *dstptr++ = dr;
+        }
+
+      srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip);
+      dstptr += dstrowskip;
+    }
+}
+
+void
+grub_video_i386_vbeblit_BGR888_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
+                                          struct grub_video_i386_vbeblit_info *src,
+                                          int x, int y, int width, int height,
+                                          int offset_x, int offset_y)
+{
+  grub_uint32_t *srcptr;
+  grub_uint8_t *dstptr;
+  unsigned srcrowskip;
+  unsigned dstrowskip;
+  int i;
+  int j;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  srcrowskip =
+    src->mode_info->pitch - src->mode_info->bytes_per_pixel * width;
+  dstrowskip =
+    dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  srcptr = (grub_uint32_t *) get_data_ptr (src, offset_x, offset_y);
+  dstptr = (grub_uint8_t *) get_data_ptr (dst, x, y);
+
+  for (j = 0; j < height; j++)
+    {
+      for (i = 0; i < width; i++)
+        {
+          grub_uint32_t color;
+          grub_uint8_t sr;
+          grub_uint8_t sg;
+          grub_uint8_t sb;
+
+          color = *srcptr++;
+
+          sr = (color >> 0) & 0xFF;
+          sg = (color >> 8) & 0xFF;
+          sb = (color >> 16) & 0xFF;
+
+          *dstptr++ = sb;
+          *dstptr++ = sg;
+          *dstptr++ = sr;
+        }
+
+      srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip);
+      dstptr += dstrowskip;
+    }
+}
+
+void
+grub_video_i386_vbeblit_RGBA8888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
                                            struct grub_video_i386_vbeblit_info *src,
                                            int x, int y, int width, int height,
                                            int offset_x, int offset_y)
@@ -101,10 +437,10 @@
 }
 
 void
-grub_video_i386_vbeblit_R8G8B8X8_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
-                                           struct grub_video_i386_vbeblit_info *src,
-                                           int x, int y, int width, int height,
-                                           int offset_x, int offset_y)
+grub_video_i386_vbeblit_direct32_copy (struct grub_video_i386_vbeblit_info *dst,
+                                       struct grub_video_i386_vbeblit_info *src,
+                                       int x, int y, int width, int height,
+                                       int offset_x, int offset_y)
 {
   int j;
   grub_uint32_t *srcptr;
@@ -126,7 +462,7 @@
 }
 
 void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_RGB888_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
                                          struct grub_video_i386_vbeblit_info *src,
                                          int x, int y, int width, int height,
                                          int offset_x, int offset_y)
@@ -193,7 +529,7 @@
 }
 
 void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_RGB888_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
                                          struct grub_video_i386_vbeblit_info *src,
                                          int x, int y, int width, int height,
                                          int offset_x, int offset_y)
@@ -231,7 +567,7 @@
 }
 
 void
-grub_video_i386_vbeblit_index_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_index_RGBA8888 (struct grub_video_i386_vbeblit_info *dst,
                                         struct grub_video_i386_vbeblit_info *src,
                                         int x, int y, int width, int height,
                                         int offset_x, int offset_y)
@@ -295,7 +631,7 @@
 }
 
 void
-grub_video_i386_vbeblit_index_R8G8B8X8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_index_RGBX8888 (struct grub_video_i386_vbeblit_info *dst,
                                         struct grub_video_i386_vbeblit_info *src,
                                         int x, int y, int width, int height,
                                         int offset_x, int offset_y)
@@ -332,7 +668,7 @@
 }
 
 void
-grub_video_i386_vbeblit_R8G8B8A8_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_RGBA8888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
                                          struct grub_video_i386_vbeblit_info *src,
                                          int x, int y, int width, int height,
                                          int offset_x, int offset_y)
@@ -368,7 +704,7 @@
 }
 
 void
-grub_video_i386_vbeblit_R8G8B8_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_RGB888_RGB888 (struct grub_video_i386_vbeblit_info *dst,
                                        struct grub_video_i386_vbeblit_info *src,
                                        int x, int y, int width, int height,
                                        int offset_x, int offset_y)
@@ -393,7 +729,7 @@
 }
 
 void
-grub_video_i386_vbeblit_index_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbeblit_index_RGB888 (struct grub_video_i386_vbeblit_info *dst,
                                       struct grub_video_i386_vbeblit_info *src,
                                       int x, int y, int width, int height,
                                       int offset_x, int offset_y)

=== modified file 'video/i386/pc/vbefill.c'
--- video/i386/pc/vbefill.c	2007-07-21 22:32:33 +0000
+++ video/i386/pc/vbefill.c	2008-07-03 13:49:18 +0000
@@ -34,51 +34,63 @@
 #include <grub/video.h>
 
 void
-grub_video_i386_vbefill_R8G8B8A8 (struct grub_video_i386_vbeblit_info *dst,
+grub_video_i386_vbefill_direct32 (struct grub_video_i386_vbeblit_info *dst,
                                   grub_video_color_t color, int x, int y,
                                   int width, int height)
 {
   int i;
   int j;
   grub_uint32_t *dstptr;
-
-  /* We do not need to worry about data being out of bounds
-     as we assume that everything has been checked before.  */
+  grub_size_t rowskip;
+
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  /* Get the start address. */
+  dstptr = (grub_uint32_t *) grub_video_vbe_get_video_ptr (dst, x, y);
 
   for (j = 0; j < height; j++)
     {
-      dstptr = (grub_uint32_t *)grub_video_vbe_get_video_ptr (dst, x, y + j);
-
       for (i = 0; i < width; i++)
         *dstptr++ = color;
+
+      /* Advance the dest pointer to the right location on the next line. */
+      dstptr = (grub_uint32_t *) (((char *) dstptr) + rowskip);
     }
 }
 
 void
-grub_video_i386_vbefill_R8G8B8 (struct grub_video_i386_vbeblit_info *dst,
-                                grub_video_color_t color, int x, int y,
-                                int width, int height)
+grub_video_i386_vbefill_direct24 (struct grub_video_i386_vbeblit_info *dst,
+                                  grub_video_color_t color, int x, int y,
+                                  int width, int height)
 {
   int i;
   int j;
+  grub_size_t rowskip;
   grub_uint8_t *dstptr;
-  grub_uint8_t fillr = (grub_uint8_t)((color >> 0) & 0xFF);
-  grub_uint8_t fillg = (grub_uint8_t)((color >> 8) & 0xFF);
-  grub_uint8_t fillb = (grub_uint8_t)((color >> 16) & 0xFF);
+  grub_uint8_t fill0 = (grub_uint8_t)((color >> 0) & 0xFF);
+  grub_uint8_t fill1 = (grub_uint8_t)((color >> 8) & 0xFF);
+  grub_uint8_t fill2 = (grub_uint8_t)((color >> 16) & 0xFF);
 
-  /* We do not need to worry about data being out of bounds
-     as we assume that everything has been checked before.  */
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+  
+  /* Get the start address. */
+  dstptr = (grub_uint8_t *) grub_video_vbe_get_video_ptr (dst, x, y);
 
   for (j = 0; j < height; j++)
     {
-      dstptr = (grub_uint8_t *)grub_video_vbe_get_video_ptr (dst, x, y + j);
-
       for (i = 0; i < width; i++)
         {
-          *dstptr++ = fillr;
-          *dstptr++ = fillg;
-          *dstptr++ = fillb;
+          *dstptr++ = fill0;
+          *dstptr++ = fill1;
+          *dstptr++ = fill2;
         }
+
+      /* Advance the dest pointer to the right location on the next line. */
+      dstptr += rowskip;
     }
 }
 
@@ -89,18 +101,24 @@
 {
   int i;
   int j;
+  grub_size_t rowskip;
   grub_uint8_t *dstptr;
   grub_uint8_t fill = (grub_uint8_t)color & 0xFF;
 
-  /* We do not need to worry about data being out of bounds
-     as we assume that everything has been checked before.  */
+  /* Calculate the number of bytes to advance from the end of one line
+   * to the beginning of the next line. */
+  rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width;
+
+  /* Get the start address. */
+  dstptr = (grub_uint8_t *) grub_video_vbe_get_video_ptr (dst, x, y);
 
   for (j = 0; j < height; j++)
     {
-      dstptr = (grub_uint8_t *)grub_video_vbe_get_video_ptr (dst, x, y + j);
-
       for (i = 0; i < width; i++)
         *dstptr++ = fill;
+      
+      /* Advance the dest pointer to the right location on the next line. */
+      dstptr += rowskip;
     }
 }
 
@@ -112,9 +130,6 @@
   int i;
   int j;
 
-  /* We do not need to worry about data being out of bounds
-     as we assume that everything has been checked before.  */
-
   for (j = 0; j < height; j++)
     for (i = 0; i < width; i++)
       set_pixel (dst, x+i, y+j, color);

=== modified file 'video/i386/pc/vbeutil.c'
--- video/i386/pc/vbeutil.c	2007-07-21 22:32:33 +0000
+++ video/i386/pc/vbeutil.c	2008-07-03 14:10:25 +0000
@@ -52,6 +52,11 @@
             + y * source->mode_info->pitch
             + x;
       break;
+
+    /* case 1: */
+      /* For 1-bit bitmaps, addressing needs to be done at the bit level
+       * and it doesn't make sense, in general, to ask for a pointer
+       * to a particular pixel's data. */
     }
 
   return ptr;
@@ -86,6 +91,17 @@
       color = *(grub_uint8_t *)get_data_ptr (source, x, y);
       break;
 
+    case 1:
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+        {
+          int bit_index = y * source->mode_info->width + x;
+          grub_uint8_t *ptr = (grub_uint8_t *)source->data
+                              + bit_index / 8;
+          int bit_pos = 7 - bit_index % 8;
+          color = (*ptr >> bit_pos) & 0x01;
+        }
+      break;
+
     default:
       break;
     }
@@ -143,6 +159,17 @@
       }
       break;
 
+    case 1:
+      if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED)
+        {
+          int bit_index = y * source->mode_info->width + x;
+          grub_uint8_t *ptr = (grub_uint8_t *)source->data
+                              + bit_index / 8;
+          int bit_pos = 7 - bit_index % 8;
+          *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos);
+        }
+      break;
+
     default:
       break;
     }

=== modified file 'video/readers/jpeg.c'
--- video/readers/jpeg.c	2008-08-01 03:06:55 +0000
+++ video/readers/jpeg.c	2008-08-03 03:57:46 +0000
@@ -1,20 +1,20 @@
 /*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
+*  GRUB  --  GRand Unified Bootloader
+*  Copyright (C) 2008  Free Software Foundation, Inc.
+*
+*  GRUB is free software: you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include <grub/bitmap.h>
 #include <grub/types.h>
@@ -542,7 +542,7 @@
 
   if (grub_video_bitmap_create (data->bitmap, data->image_width,
 				data->image_height,
-				GRUB_VIDEO_BLIT_FORMAT_R8G8B8))
+				GRUB_VIDEO_BLIT_FORMAT_RGB_888))
     return grub_errno;
 
   data->bit_mask = 0x0;

=== modified file 'video/readers/png.c'
--- video/readers/png.c	2008-08-01 03:06:55 +0000
+++ video/readers/png.c	2008-08-03 04:00:22 +0000
@@ -231,7 +231,7 @@
     {
       if (grub_video_bitmap_create (data->bitmap, data->image_width,
 				    data->image_height,
-				    GRUB_VIDEO_BLIT_FORMAT_R8G8B8))
+				    GRUB_VIDEO_BLIT_FORMAT_RGB_888))
 	return grub_errno;
       data->bpp = 3;
     }
@@ -239,7 +239,7 @@
     {
       if (grub_video_bitmap_create (data->bitmap, data->image_width,
 				    data->image_height,
-				    GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8))
+				    GRUB_VIDEO_BLIT_FORMAT_RGBA_8888))
 	return grub_errno;
       data->bpp = 4;
     }

=== modified file 'video/readers/tga.c'
--- video/readers/tga.c	2008-08-01 03:06:55 +0000
+++ video/readers/tga.c	2008-08-03 03:57:46 +0000
@@ -397,7 +397,7 @@
     {
       grub_video_bitmap_create (bitmap, header.image_width,
                                 header.image_height,
-                                GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8);
+                                GRUB_VIDEO_BLIT_FORMAT_RGBA_8888);
       if (grub_errno != GRUB_ERR_NONE)
         {
           grub_file_close (file);
@@ -420,7 +420,7 @@
     {
       grub_video_bitmap_create (bitmap, header.image_width,
                                 header.image_height,
-                                GRUB_VIDEO_BLIT_FORMAT_R8G8B8);
+                                GRUB_VIDEO_BLIT_FORMAT_RGB_888);
       if (grub_errno != GRUB_ERR_NONE)
         {
           grub_file_close (file);

=== added file 'video/setmode.c'
--- video/setmode.c	1970-01-01 00:00:00 +0000
+++ video/setmode.c	2008-07-19 19:31:46 +0000
@@ -0,0 +1,249 @@
+/* video/setmode.c - Smart video mode selection based on preferences. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/video.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+/* Set the video mode based on the preferred modes specified in MODE_LIST in
+   the form: <width>x<height>[x<depth>][;...]
+
+   For example:  640x480;800x600x8;400x300x32
+
+   If MODE_LIST is null, or no modes in it are usable, then DEFAULT_WIDTH and
+   DEFAULT_HEIGHT are used to set the mode.  The MODE_FLAGS argument determines
+   the video mode flags such as double buffering that are used.  */
+
+grub_err_t
+grub_video_setup_preferred_mode (const char *mode_list, int mode_flags,
+                                 int default_width, int default_height)
+{
+  int mode_found = 0;
+
+  if (mode_list != NULL)
+    {
+      /* Take copy of mode_list as we don't want tat.  */
+      char *const modes_copy = grub_strdup (mode_list);
+      if (modes_copy == NULL)
+        return grub_errno;
+
+      /* Initialize next mode.  */
+      char *next_mode = modes_copy;
+
+      /* Loop until all modes has been tested out.  */
+      while ((next_mode != NULL) && !mode_found)
+        {
+          /* Use last next_mode as current mode.  */
+          char *tmp = next_mode;
+
+          int width = -1;
+          int height = -1;
+          int depth = -1;
+
+          /* Save position of next mode and separate modes.  */
+          next_mode = grub_strchr(next_mode, ';');
+          if (next_mode)
+            {
+              *next_mode = 0;
+              next_mode++;
+            }
+
+          /* Skip whitespace.  */
+          while (grub_isspace (*tmp))
+            tmp++;
+
+          /* Initialize token holders.  */
+          char *current_mode = tmp;
+          char *param = tmp;
+          char *value = NULL;
+
+          /* Parse <width>x<height>[x<depth>]*/
+
+          /* Find width value.  */
+          value = param;
+          param = grub_strchr(param, 'x');
+          if (param == NULL)
+            {
+              grub_err_t rc;
+
+              /* First setup error message.  */
+              rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                               "Invalid mode: %s\n",
+                               current_mode);
+
+              /* Free memory before returning.  */
+              grub_free (modes_copy);
+
+              return rc;
+            }
+
+          *param = 0;
+          param++;
+
+          width = grub_strtoul (value, 0, 0);
+          if (grub_errno != GRUB_ERR_NONE)
+            {
+              grub_err_t rc;
+
+              /* First setup error message.  */
+              rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                               "Invalid mode: %s\n",
+                               current_mode);
+
+              /* Free memory before returning.  */
+              grub_free (modes_copy);
+
+              return rc;
+            }
+
+          /* Find height value.  */
+          value = param;
+          param = grub_strchr(param, 'x');
+          if (param == NULL)
+            {
+              height = grub_strtoul (value, 0, 0);
+              if (grub_errno != GRUB_ERR_NONE)
+                {
+                  grub_err_t rc;
+
+                  /* First setup error message.  */
+                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                                   "Invalid mode: %s\n",
+                                   current_mode);
+
+                  /* Free memory before returning.  */
+                  grub_free (modes_copy);
+
+                  return rc;
+                }
+            }
+          else
+            {
+              /* We have optional color depth value.  */
+              *param = 0;
+              param++;
+
+              height = grub_strtoul (value, 0, 0);
+              if (grub_errno != GRUB_ERR_NONE)
+                {
+                  grub_err_t rc;
+
+                  /* First setup error message.  */
+                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                                   "Invalid mode: %s\n",
+                                   current_mode);
+
+                  /* Free memory before returning.  */
+                  grub_free (modes_copy);
+
+                  return rc;
+                }
+
+              /* Convert color depth value.  */
+              value = param;
+              depth = grub_strtoul (value, 0, 0);
+              if (grub_errno != GRUB_ERR_NONE)
+                {
+                  grub_err_t rc;
+
+                  /* First setup error message.  */
+                  rc = grub_error (GRUB_ERR_BAD_ARGUMENT, 
+                                   "Invalid mode: %s\n",
+                                   current_mode);
+
+                  /* Free memory before returning.  */
+                  grub_free (modes_copy);
+
+                  return rc;
+                }
+            }
+
+          /* Try out video mode.  */
+
+          int flags = mode_flags;
+          /* If we have <= 8 bits, assume it is an indexed color mode.  */
+          if ((depth <= 8) && (depth != -1))
+            flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
+
+          /* We have > 8 bits; assume that it is RGB color mode.  */
+          if (depth > 8)
+            flags |= GRUB_VIDEO_MODE_TYPE_RGB;
+
+          /* If user requested specific depth, pass the request to driver.  */
+          if (depth != -1)
+            flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
+              & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
+
+          /* Try to initialize requested mode.  Ignore any errors.  */
+          grub_error_push ();
+          if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
+            {
+              grub_error_pop ();
+              continue;
+            }
+
+          /* Figure out what mode we ended up.  */
+          struct grub_video_mode_info mode_info;
+          if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+            {
+              /* Couldn't get video mode info, restore old mode
+                 and continue to next one.  */
+              grub_error_pop ();
+
+              grub_video_restore ();
+              continue;
+            }
+
+          /* Restore state of error stack.  */
+          grub_error_pop ();
+
+          /* Mode found!  Exit loop.  */
+          mode_found = 1;
+        }
+
+      /* Free memory.  */
+      grub_free (modes_copy);
+    }
+
+  if (!mode_found)
+    {
+      /* No gfxmode variable set, or no listed mode was supported.
+         Use the caller-specified defaults.  */
+      int flags = mode_flags | GRUB_VIDEO_MODE_TYPE_RGB;
+
+      /* Initialize user requested mode.  */
+      if (grub_video_setup (default_width, default_height, flags) 
+          != GRUB_ERR_NONE)
+        return grub_errno;
+
+      /* Figure out what mode we ended up.  */
+      struct grub_video_mode_info mode_info;
+      if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
+        grub_video_restore ();
+      else
+        mode_found = 1;
+    }
+
+  if (!mode_found)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       "No suitable mode found.");
+
+  return (grub_errno = GRUB_ERR_NONE);
+}

=== modified file 'video/video.c'
--- video/video.c	2008-01-01 12:02:07 +0000
+++ video/video.c	2008-07-09 16:50:11 +0000
@@ -152,15 +152,22 @@
   if (mode_info->bpp == 32)
     {
       if ((mode_info->red_mask_size == 8)
+          && (mode_info->red_field_pos == 16)
+          && (mode_info->green_mask_size == 8)
+          && (mode_info->green_field_pos == 8)
+          && (mode_info->blue_mask_size == 8)
+          && (mode_info->blue_field_pos == 0))
+        {
+          return GRUB_VIDEO_BLIT_FORMAT_BGRA_8888;
+        }
+      if ((mode_info->red_mask_size == 8)
           && (mode_info->red_field_pos == 0)
           && (mode_info->green_mask_size == 8)
           && (mode_info->green_field_pos == 8)
           && (mode_info->blue_mask_size == 8)
-          && (mode_info->blue_field_pos == 16)
-          && (mode_info->reserved_mask_size == 8)
-          && (mode_info->reserved_field_pos == 24))
+          && (mode_info->blue_field_pos == 16))
         {
-          return GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8;
+          return GRUB_VIDEO_BLIT_FORMAT_RGBA_8888;
         }
     }
 
@@ -168,13 +175,22 @@
   if (mode_info->bpp == 24)
     {
       if ((mode_info->red_mask_size == 8)
+          && (mode_info->red_field_pos == 16)
+          && (mode_info->green_mask_size == 8)
+          && (mode_info->green_field_pos == 8)
+          && (mode_info->blue_mask_size == 8)
+          && (mode_info->blue_field_pos == 0))
+        {
+          return GRUB_VIDEO_BLIT_FORMAT_BGR_888;
+        }
+      if ((mode_info->red_mask_size == 8)
           && (mode_info->red_field_pos == 0)
           && (mode_info->green_mask_size == 8)
           && (mode_info->green_field_pos == 8)
           && (mode_info->blue_mask_size == 8)
           && (mode_info->blue_field_pos == 16))
         {
-          return GRUB_VIDEO_BLIT_FORMAT_R8G8B8;
+          return GRUB_VIDEO_BLIT_FORMAT_RGB_888;
         }
     }
 
@@ -305,6 +321,19 @@
   return grub_video_adapter_active->blit_glyph (glyph, color, x, y);
 }
 
+/* Draw string to screen using specified color and font.  */
+grub_err_t
+grub_video_draw_string (const char *str, grub_font_t font, 
+                        grub_video_color_t color, 
+                        int left_x, int baseline_y)
+{
+  if (! grub_video_adapter_active)
+    return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated");
+
+  return grub_video_adapter_active->draw_string (str, font, color, 
+                                                 left_x, baseline_y);
+}
+
 /* Blit bitmap to screen.  */
 grub_err_t
 grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,

# Begin bundle
IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWYxiW6UCvHP/gH//////////
//////////9jq798BG+3fd14uW52buU+b6S6wiMzoe+zxN4dU0Z13Apc+r3vr749AiKpJRJ0fVHk
16qpQFD1uQZAus6+jqR6x7brL2b3Nfet3PtgAAPo11tY6NF2aAAClFJSFA6B53ven3qnU7Yvm5Ud
5fQs2Nfd9cH3VPYbb667vUFADz7fdJR9sUCqvd7jVJASF4PpQAZ12aAdDPdffdvTm+F699mF73wn
2553vNX3rW7DHMyvdnJd57caRSa5cvevTd6F25r2rOHqqJ1g6aFKMtdrntdfa2XK+HVAGvLUYUAC
+GVRnnvPL3PvgAXh7vb64A+269DtZ66AC7MGgVIyKAkAabWtYBVA2B9zoBCBe9uebTu6cvY27u5O
2JUd7x6fCwesyfLFuuzM7ixA+kDu40Og+ew6Lfcd8mA8O27e9h9vvOO++fV9nUj7pZ6eXWgCvvWb
5h0B75WM2ZPns3Yb27t5zUvO7qonu9T6vs9vh0409oOPKSg76Ke1g3PdYF1qUX3dxzDbHdg9u92u
02pYzdznbXbu89e9uvbPTo99Zsb775726DmyhIevaapWe3Toega71tGV7Pffa172g++fc733DPd7
xdtV9nzkTXfboVACgu2pSQJJGjL3d1Oy589p7s+h515859g1e2djPvn3S9PdXY3bW7AAB5VvNN9U
+m2ZUMOm1OuF2HgFB0Ru8+sfe73qvQ749rdN5w9VVdaBoU97J7Ze7zb3Pu7i96ca67u918t33zfP
vV9es8uXfV67vD33s3ue2i9dX3q0noABtgACgGjQAAB9H0DkClAPQAAAAANAAAAAAoEgAAAAACgA
A9HfH0IFIFKkT20AU6ANUGt8+1rykBrSu76O+2fRI218+3vt18L2N6wUo983VKopS+e93nod2U7Y
AJBQe2kdfHNXz17nvvPTju3MyunOkfe87xNbR9lKBH0IgUPu+nvs+cqmLvmrW1j0Hu9l7z6863zz
o+OKWoAWPh4l7zOr47y9n0ap689e+77nZUOtVxVr4QHPvere4nve+pFsz68Ojnzbd2dUIu53Kfdx
di23e+n14BnfE7LRvX2+e5meqtbbYqxfdzrUwa3vt3n0HveOmTSpUA0MmwCvbOqVUoDEBZ99g54M
lX2ykBR2ehn3uiqBVB0BZ9DOBkJUoUGt0OU5oERXrXQ01gRsxVCgBoW+57YH1x8bo+utX3e903Y6
bb619s+7tzfNrfc59D1STT60euh7rUC2Ps4c18Wh3Yc+zqj0HTrp0G7DXzPXp8eKkiRK9aDWEc9v
cNfDHvh3idY+nvjLMakhDO4520q2m77JvcC9mgePY5C4V1eu7e6oVXe4c6dPo87aPR33jHM0MFDZ
u7uqgo22d7eQhQAIpR57NqtxqqAdtdmarC7Y++e+99te7veuHOjR26LcOt3cPWK7NnudOhu1sPn1
d72+zl3LeugPV940fedAMI1kC+zbGlV7maH2UDPe3fPm7Boz3zGjX03zOXp10e2672daK52O7eQ6
063THdb3d73o9C9S2kJW9gdsO9rdjzyiewvR13N299ID7xa3325727WjTrusuW8tPa59Za570TYa
Cdc6olV12XLbN2Odw3GFtN11s6eLsyxnetIT6559974OgucfavenqLtPJ9HB1ts2bCGJPrzTNkql
e3d8AHvd732985a0h49ffffe99zm+uPq67vr3E9TpJN3JccgM43bHSmW7uiDpKzdu1UooF73CjlR
p1R298NAe0+vXt977eG970x93dsbu5XfWvLQK99dylPeO7AA53u9A9Z497rwNABoAoBVsAB5A95h
trt0HXzYBIPvrDvm+9AANCeg+2fZq4Pp8+HcXW3u70D7wAKvm+eusvuzhRXz3dHc7tt1juZp27tO
t0durrjkXr4Kle+3D7a3TyttHZ4933Gjjyl9jFIFAAzYZ2DUlm69a3tbvM65vgHke+y9glNF9KVv
du+9uvcW00u1uXFXHveHWIesN7Z7ye3c93Q6Yu7d1wLWNHG7TIiGUUcwocpHZdbWDbAOlphyTMxY
7rSbrZiBu5wKAOcp612yFHukLYNVLTnZ06NHbuteiu9tve3vZ67cKk13dyc1dADEDnc3Z3b1u3lm
2x3anRhQbknLxpPSvbRrvdZjRrUwcydzveeiiyzZcbS1buNte1489Vevvlg99HuXY4X1EGwpt7e8
BvbVgHLoae2O7AB0B2tPTtnup6tt15NqgzdXZO7DnDu3TagnMys2u5bZmNV08gHSh21Ejq7ubnOV
ve9beV2uu++bZVe7w+7duM3A0Aap2h24ASpQ1pF1kzmMgmpDSAk7vXvemsbnNZZbu17L3vaysFrG
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
YMLBgoGMGDE8GDGDGDGFgxjBieDGJWYVFFVqlapWpXAgVLFhHTDiiUpABlDNTy66Pbh17doc9GTo
NxQgqQhhcDyv7piPZgC5557kKUm49HDJxCTnAfWIwhJaIjkgOREO7FogGMRTlt1ywjZBJD1OHlyJ
pifa0kUzVEUzUTUiSLIEhISDJJImcznrxzbOynwz+GW7h5+BRHROMRCAInF3oDIyCJtvjLjxqzPj
sxkimTT8K2rwcB9xdIMoxGU/oWxrYL59UkybmUjCdueV82Dc+fOfqu5+/V+WcTskolICRDgEDpiG
O9HVabQ0/MSQkzCaU76kieJspVxKmiWQikgdYKJhB3DnamiiI4YUlQTF2zQCvnsKTFpIEIhH1aB9
r31FdvfVgcuaecKsV4RTUJtwk048mZmElJEg184gQBc6wAPCI3nvMpBbx+tcker6Y5OvoIbLX4fX
3z9RR+o/fdn5fo5PZ+ju8nh6vt6NZOHJ3dX29XN4eThyfoxJ6cNHp08JNH9M+Gz6PDp8Pss6cPs/
BoqfhV1e67vW91y5fC9bXrfC+N8L3Xvq6vO+NyfF7qta+F4vda+Fr2vdcvha87yu73Xc17Xi910s
s4aPhR6cNkn4LMmOkmSz8Gzho/B9n2UyeTJl22268k314ILNxuc3DHar37j2s81VEytqdnmvpNtK
qt5t43EU4tblwM63K0N8fHtHc25pWWWL0m/K5LzzGBaZbdKNrxv4ynv4dzspb9jmN+eiaWRSVqvf
Z0rdng5NcqWvvSqrfLJBblY3C3DGwPi+luZohKjj3y8zbG7+p25N1plg/VeVFs6Q8G7YV6z13aJT
lKpSsxkbn0wpRwbJUPdKTzJ976S22R1ScLDPaOKJrjR+Rwu7Fj2Cv4LnlzSmFtdX14pHfTfVLd1x
RzvQNhqrcaomm0OcL3W55i7s06bbjREs3Y81sXBtHOzhSg26TrPnh3TjWt+Zznde7Rd8gWDtN/CJ
uN/FDSzhhvvtBX5XxwITknJya0thlKhIIzhcmXTrtSLyfPjfx3PshBCzTSWLxmd8MG828dOPDlw3
0u58Zc8G77uOrc88IEr+i8S35m3hrKOM41ujGqd3G9qacncV6bx3YinRr7avINN0tYeuJadp4Zpu
hJN3lWW7yVMmkljNGrF5KTt/Diu2GnZk0pdGuWu7uPzRx1FOZtZs1Ie93h2tsYkzxfcXmItDOksp
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
