xtables-addons: move to package/, add myself as maintainer
authorjow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 17 Jan 2013 12:29:26 +0000 (12:29 +0000)
committerjow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Thu, 17 Jan 2013 12:29:26 +0000 (12:29 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@35193 3c298f89-4303-0410-b956-a3cf2f4a3e73

18 files changed:
package/network/utils/xtables-addons/Makefile [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/001-no_depmod.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/002-fix-kernel-version-detection.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/003-redundant-bracket.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/100-add-rtsp-conntrack.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/101-rtsp-linux-3.6-compat.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/200-add-lua-packetscript.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/201-fix-lua-packetscript.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches-1.x/300-geoip-endian-detection.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/001-no_depmod.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/002-fix-kernel-version-detection.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/200-add-lua-packetscript.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/201-fix-lua-packetscript.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/300-geoip-endian-detection.patch [new file with mode: 0644]
package/network/utils/xtables-addons/patches/400-uid-gid-linux-3.7-compat.patch [new file with mode: 0644]

diff --git a/package/network/utils/xtables-addons/Makefile b/package/network/utils/xtables-addons/Makefile
new file mode 100644 (file)
index 0000000..aabc698
--- /dev/null
@@ -0,0 +1,158 @@
+#
+# Copyright (C) 2009-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=xtables-addons
+ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,3.7.0)),1)
+PKG_VERSION:=2.1
+PKG_RELEASE:=1
+PKG_MD5SUM:=b624fc57bbda9e15c33a6471e4ec75e1
+else
+PKG_VERSION:=1.45
+PKG_RELEASE:=3
+PKG_MD5SUM:=802d2f556a5e545f44e4b69937bf8490
+PATCH_DIR:=./patches-1.x
+endif
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@SF/xtables-addons
+PKG_BUILD_DEPENDS:=iptables
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+PKG_MAINTAINER:=Jo-Philipp Wich <jow@openwrt.org>
+
+PKG_FIXUP:=autoreconf
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/xtables-addons
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Firewall
+  TITLE:=Extensions not distributed in the main Xtables
+  URL:=http://xtables-addons.sourceforge.net/
+endef
+
+# uses GNU configure
+
+CONFIGURE_ARGS+= \
+       --with-kbuild="$(LINUX_DIR)" \
+       --with-xtables="$(STAGING_DIR)/usr" \
+       --with-xtlibdir="/usr/lib/iptables" \
+
+define Build/Compile
+       +$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+               ARCH="$(LINUX_KARCH)" \
+               CROSS_COMPILE="$(TARGET_CROSS)" \
+               DESTDIR="$(PKG_INSTALL_DIR)" \
+               DEPMOD="/bin/true" \
+               all
+endef
+
+define Build/Install
+       $(MAKE) -C $(PKG_BUILD_DIR) \
+               ARCH="$(LINUX_KARCH)" \
+               CROSS_COMPILE="$(TARGET_CROSS)" \
+               DESTDIR="$(PKG_INSTALL_DIR)" \
+               DEPMOD="/bin/true" \
+               install
+endef
+
+# 1: extension/module suffix used in package name
+# 2: extension/module display name used in package title/description
+# 3: list of extensions to package
+# 4: list of modules to package
+# 5: module load priority
+# 6: module depends
+define BuildTemplate
+
+ ifneq ($(3),)
+  define Package/iptables-mod-$(1)
+    $$(call Package/xtables-addons)
+    CATEGORY:=Network
+    TITLE:=$(2) iptables extension
+    DEPENDS:=iptables $(if $(4),+kmod-ipt-$(1))
+  endef
+
+  define Package/iptables-mod-$(1)/install
+       $(INSTALL_DIR) $$(1)/usr/lib/iptables
+       for m in $(3); do \
+               $(CP) \
+                       $(PKG_INSTALL_DIR)/usr/lib/iptables/lib$$$$$$$${m}.so \
+                       $$(1)/usr/lib/iptables/ ; \
+       done
+  endef
+
+  $$(eval $$(call BuildPackage,iptables-mod-$(1)))
+ endif
+
+ ifneq ($(4),)
+  define KernelPackage/ipt-$(1)
+    SUBMENU:=Netfilter Extensions
+    TITLE:=$(2) netfilter module
+    DEPENDS:=kmod-ipt-core $(6)
+    KCONFIG:=$(7)
+    FILES:=$(foreach mod,$(4),$(PKG_BUILD_DIR)/extensions/$(mod).$(LINUX_KMOD_SUFFIX))
+    AUTOLOAD:=$(call AutoLoad,$(5),$(notdir $(4)))
+  endef
+
+  $$(eval $$(call KernelPackage,ipt-$(1)))
+ endif
+
+endef
+
+
+define Package/iptaccount
+  $(call Package/xtables-addons)
+  CATEGORY:=Network
+  TITLE:=iptables-mod-account control utility
+  DEPENDS:=iptables +iptables-mod-account
+endef
+
+define Package/iptaccount/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(CP) \
+               $(PKG_INSTALL_DIR)/usr/lib/libxt_ACCOUNT_cl.so* \
+               $(1)/usr/lib/
+       $(CP) \
+               $(PKG_INSTALL_DIR)/usr/sbin/iptaccount \
+               $(1)/usr/sbin/
+endef
+
+
+#$(eval $(call BuildTemplate,SUFFIX,DESCRIPTION,EXTENSION,MODULE,PRIORITY,DEPENDS))
+
+$(eval $(call BuildTemplate,compat-xtables,API compatibilty layer,,compat_xtables,45,,CONFIG_NF_CONNTRACK_MARK=y))
+$(eval $(call BuildTemplate,rawpost,RAWPOST,,iptable_rawpost $(if $(CONFIG_IPV6),ip6table_rawpost),50,+kmod-ipt-compat-xtables +IPV6:kmod-ip6tables))
+$(eval $(call BuildTemplate,nathelper-rtsp,RTSP Conntrack and NAT,,rtsp/nf_conntrack_rtsp rtsp/nf_nat_rtsp,46,+kmod-ipt-conntrack-extra))
+
+$(eval $(call BuildTemplate,account,ACCOUNT,xt_ACCOUNT,ACCOUNT/xt_ACCOUNT,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,chaos,CHAOS,xt_CHAOS,xt_CHAOS,47,+kmod-ipt-compat-xtables +kmod-ipt-delude +kmod-ipt-tarpit))
+$(eval $(call BuildTemplate,condition,Condition,xt_condition,xt_condition,46,))
+$(eval $(call BuildTemplate,delude,DELUDE,xt_DELUDE,xt_DELUDE,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,dhcpmac,DHCPMAC,xt_DHCPMAC,xt_DHCPMAC,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,dnetmap,DNETMAP,xt_DNETMAP,xt_DNETMAP,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,fuzzy,fuzzy,xt_fuzzy,xt_fuzzy,46,))
+$(eval $(call BuildTemplate,geoip,geoip,xt_geoip,xt_geoip,46,))
+$(eval $(call BuildTemplate,iface,iface,xt_iface,xt_iface,46,))
+$(eval $(call BuildTemplate,ipmark,IPMARK,xt_IPMARK,xt_IPMARK,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,ipp2p,IPP2P,xt_ipp2p,xt_ipp2p,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,ipv4options,ipv4options,xt_ipv4options,xt_ipv4options,46,))
+$(eval $(call BuildTemplate,length2,length2,xt_length2,xt_length2,46,))
+$(eval $(call BuildTemplate,logmark,LOGMARK,xt_LOGMARK,xt_LOGMARK,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,lscan,lscan,xt_lscan,xt_lscan,46,))
+$(eval $(call BuildTemplate,lua,Lua PacketScript,xt_LUA,LUA/xt_LUA,46,+kmod-ipt-conntrack-extra))
+$(eval $(call BuildTemplate,psd,psd,xt_psd,xt_psd,46,))
+$(eval $(call BuildTemplate,quota2,quota2,xt_quota2,xt_quota2,46,))
+$(eval $(call BuildTemplate,rawnat,RAWNAT,xt_RAWDNAT xt_RAWSNAT,xt_RAWNAT,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,steal,STEAL,xt_STEAL,xt_STEAL,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,sysrq,SYSRQ,xt_SYSRQ,xt_SYSRQ,46,+kmod-ipt-compat-xtables))
+$(eval $(call BuildTemplate,tarpit,TARPIT,xt_TARPIT,xt_TARPIT,46,+kmod-ipt-compat-xtables))
diff --git a/package/network/utils/xtables-addons/patches-1.x/001-no_depmod.patch b/package/network/utils/xtables-addons/patches-1.x/001-no_depmod.patch
new file mode 100644 (file)
index 0000000..9905af1
--- /dev/null
@@ -0,0 +1,16 @@
+---
+ Makefile.in |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -11,9 +11,6 @@ FORCE:
+ xtables-addons.8: FORCE
+       ${MAKE} -f Makefile.mans all;
+-install-exec-hook:
+-      depmod -a || :;
+-
+ config.status: Makefile.iptrules.in
+ tmpdir := $(shell mktemp -dtu)
diff --git a/package/network/utils/xtables-addons/patches-1.x/002-fix-kernel-version-detection.patch b/package/network/utils/xtables-addons/patches-1.x/002-fix-kernel-version-detection.patch
new file mode 100644 (file)
index 0000000..b31f9f1
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/configure
++++ b/configure
+@@ -11780,7 +11780,7 @@ regular_CFLAGS="-Wall -Waggregate-return
+ if test -n "$kbuilddir"; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel version that we will build against" >&5
+ $as_echo_n "checking kernel version that we will build against... " >&6; }
+-      krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease)";
++      krel="$(make -sC "$kbuilddir" M=$PWD kernelversion)";
+       kmajor="${krel%%[^0-9]*}";
+       kmajor="$(($kmajor+0))";
+       krel="${krel:${#kmajor}}";
+--- a/configure.ac
++++ b/configure.ac
+@@ -44,7 +44,7 @@ regular_CFLAGS="-Wall -Waggregate-return
+ if test -n "$kbuilddir"; then
+       AC_MSG_CHECKING([kernel version that we will build against])
+-      krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease)";
++      krel="$(make -sC "$kbuilddir" M=$PWD kernelversion)";
+       kmajor="${krel%%[[^0-9]]*}";
+       kmajor="$(($kmajor+0))";
+       krel="${krel:${#kmajor}}";
diff --git a/package/network/utils/xtables-addons/patches-1.x/003-redundant-bracket.patch b/package/network/utils/xtables-addons/patches-1.x/003-redundant-bracket.patch
new file mode 100644 (file)
index 0000000..ae3911a
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/configure.ac
++++ b/configure.ac
+@@ -31,7 +31,7 @@ xtlibdir="$(pkg-config --variable=xtlibd
+ AC_ARG_WITH([xtlibdir],
+       AS_HELP_STRING([--with-xtlibdir=PATH],
+-      [Path where to install Xtables extensions [[autodetect]]]]),
++      [Path where to install Xtables extensions [[autodetect]]]),
+       [xtlibdir="$withval"])
+ AC_MSG_CHECKING([Xtables module directory])
+ AC_MSG_RESULT([$xtlibdir])
diff --git a/package/network/utils/xtables-addons/patches-1.x/100-add-rtsp-conntrack.patch b/package/network/utils/xtables-addons/patches-1.x/100-add-rtsp-conntrack.patch
new file mode 100644 (file)
index 0000000..34cdc8c
--- /dev/null
@@ -0,0 +1,1334 @@
+--- /dev/null
++++ b/extensions/rtsp/Kbuild
+@@ -0,0 +1,4 @@
++# -*- Makefile -*-
++
++obj-m += nf_nat_rtsp.o
++obj-m += nf_conntrack_rtsp.o
+--- /dev/null
++++ b/extensions/rtsp/netfilter_helpers.h
+@@ -0,0 +1,133 @@
++/*
++ * Helpers for netfiler modules.  This file provides implementations for basic
++ * functions such as strncasecmp(), etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_STRNCASECMP        nf_strncasecmp()
++ *   NF_NEED_STRTOU16           nf_strtou16()
++ *   NF_NEED_STRTOU32           nf_strtou32()
++ */
++#ifndef _NETFILTER_HELPERS_H
++#define _NETFILTER_HELPERS_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++#define iseol(c) ( (c) == '\r' || (c) == '\n' )
++
++/*
++ * The standard strncasecmp()
++ */
++#ifdef NF_NEED_STRNCASECMP
++static int
++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
++{
++    if (s1 == NULL || s2 == NULL)
++    {
++        if (s1 == NULL && s2 == NULL)
++        {
++            return 0;
++        }
++        return (s1 == NULL) ? -1 : 1;
++    }
++    while (len > 0 && tolower(*s1) == tolower(*s2))
++    {
++        len--;
++        s1++;
++        s2++;
++    }
++    return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
++}
++#endif /* NF_NEED_STRNCASECMP */
++
++/*
++ * Parse a string containing a 16-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU16
++static int
++nf_strtou16(const char* pbuf, u_int16_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (isdigit(pbuf[n]))
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU16 */
++
++/*
++ * Parse a string containing a 32-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU32
++static int
++nf_strtou32(const char* pbuf, u_int32_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (pbuf[n] >= '0' && pbuf[n] <= '9')
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU32 */
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.
++ */
++#ifdef NF_NEED_NEXTLINE
++static int
++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    while (p[off] != '\n')
++    {
++        if (len-off <= 1)
++        {
++            return 0;
++        }
++
++        physlen++;
++        off++;
++    }
++
++    /* if we saw a crlf, physlen needs adjusted */
++    if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++    {
++        physlen--;
++    }
++
++    /* advance past the newline */
++    off++;
++
++    *plineoff = *poff;
++    *plinelen = physlen;
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_HELPERS_H */
+--- /dev/null
++++ b/extensions/rtsp/netfilter_mime.h
+@@ -0,0 +1,89 @@
++/*
++ * MIME functions for netfilter modules.  This file provides implementations
++ * for basic MIME parsing.  MIME headers are used in many protocols, such as
++ * HTTP, RTSP, SIP, etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_MIME_NEXTLINE      nf_mime_nextline()
++ */
++#ifndef _NETFILTER_MIME_H
++#define _NETFILTER_MIME_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.  If the current line is empty, *plinelen will be set to zero.  If
++ * not, it will be set to the actual line length (including CRLF).
++ *
++ * 'line' in this context means logical line (includes LWS continuations).
++ * Returns 1 on success, 0 on failure.
++ */
++#ifdef NF_NEED_MIME_NEXTLINE
++static int
++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++    int     is_first_line = 1;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    do
++    {
++        while (p[off] != '\n')
++        {
++            if (len-off <= 1)
++            {
++                return 0;
++            }
++
++            physlen++;
++            off++;
++        }
++
++        /* if we saw a crlf, physlen needs adjusted */
++        if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++        {
++            physlen--;
++        }
++
++        /* advance past the newline */
++        off++;
++
++        /* check for an empty line */
++        if (physlen == 0)
++        {
++            break;
++        }
++
++        /* check for colon on the first physical line */
++        if (is_first_line)
++        {
++            is_first_line = 0;
++            if (memchr(p+(*poff), ':', physlen) == NULL)
++            {
++                return 0;
++            }
++        }
++    }
++    while (p[off] == ' ' || p[off] == '\t');
++
++    *plineoff = *poff;
++    *plinelen = (physlen == 0) ? 0 : (off - *poff);
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_MIME_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_MIME_H */
+--- /dev/null
++++ b/extensions/rtsp/nf_conntrack_rtsp.c
+@@ -0,0 +1,519 @@
++/*
++ * RTSP extension for IP connection tracking
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ * based on ip_conntrack_irc.c
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ *   insmod nf_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *                              max_outstanding=n setup_timeout=secs
++ *
++ * If no ports are specified, the default will be port 554.
++ *
++ * With max_outstanding you can define the maximum number of not yet
++ * answered SETUP requests per RTSP session (default 8).
++ * With setup_timeout you can specify how long the system waits for
++ * an expected data channel (default 300 seconds).
++ *
++ * 2005-02-13: Harald Welte <laforge at netfilter.org>
++ *    - port to 2.6
++ *    - update to recent post-2.6.11 api changes
++ * 2006-09-14: Steven Van Acker <deepstar at singularity.be>
++ *      - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack
++ * 2007-04-18: Michael Guntsche <mike at it-loops.com>
++ *                    - Port to new NF API
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/inet.h>
++#include <net/tcp.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_expect.h>
++#include <net/netfilter/nf_conntrack_helper.h>
++#include "nf_conntrack_rtsp.h"
++
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#define NF_NEED_STRTOU32
++#define NF_NEED_NEXTLINE
++#include "netfilter_helpers.h"
++#define NF_NEED_MIME_NEXTLINE
++#include "netfilter_mime.h"
++
++#include <linux/ctype.h>
++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int num_ports = 0;
++static int max_outstanding = 8;
++static unsigned int setup_timeout = 300;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
++MODULE_DESCRIPTION("RTSP connection tracking module");
++MODULE_LICENSE("GPL");
++module_param_array(ports, int, &num_ports, 0400);
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++module_param(max_outstanding, int, 0400);
++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
++module_param(setup_timeout, int, 0400);
++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
++
++static char *rtsp_buffer;
++static DEFINE_SPINLOCK(rtsp_buffer_lock);
++
++static struct nf_conntrack_expect_policy rtsp_exp_policy; 
++
++unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
++                               enum ip_conntrack_info ctinfo,
++                               unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp,
++                               struct nf_conntrack_expect *exp);
++void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
++
++EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook);
++
++/*
++ * Max mappings we will allow for one RTSP connection (for RTP, the number
++ * of allocated ports is twice this value).  Note that SMIL burns a lot of
++ * ports so keep this reasonably high.  If this is too low, you will see a
++ * lot of "no free client map entries" messages.
++ */
++#define MAX_PORT_MAPS 16
++
++/*** default port list was here in the masq code: 554, 3030, 4040 ***/
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*
++ * Parse an RTSP packet.
++ *
++ * Returns zero if parsing failed.
++ *
++ * Parameters:
++ *  IN      ptcp        tcp data pointer
++ *  IN      tcplen      tcp data len
++ *  IN/OUT  ptcpoff     points to current tcp offset
++ *  OUT     phdrsoff    set to offset of rtsp headers
++ *  OUT     phdrslen    set to length of rtsp headers
++ *  OUT     pcseqoff    set to offset of CSeq header
++ *  OUT     pcseqlen    set to length of CSeq header
++ */
++static int
++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
++                   uint* phdrsoff, uint* phdrslen,
++                   uint* pcseqoff, uint* pcseqlen,
++                   uint* transoff, uint* translen)
++{
++      uint    entitylen = 0;
++      uint    lineoff;
++      uint    linelen;
++      
++      if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++              return 0;
++      
++      *phdrsoff = *ptcpoff;
++      while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) {
++              if (linelen == 0) {
++                      if (entitylen > 0)
++                              *ptcpoff += min(entitylen, tcplen - *ptcpoff);
++                      break;
++              }
++              if (lineoff+linelen > tcplen) {
++                      pr_info("!! overrun !!\n");
++                      break;
++              }
++              
++              if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
++                      *pcseqoff = lineoff;
++                      *pcseqlen = linelen;
++              } 
++
++              if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
++                      *transoff = lineoff;
++                      *translen = linelen;
++              }
++              
++              if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) {
++                      uint off = lineoff+15;
++                      SKIP_WSPACE(ptcp+lineoff, linelen, off);
++                      nf_strtou32(ptcp+off, &entitylen);
++              }
++      }
++      *phdrslen = (*ptcpoff) - (*phdrsoff);
++      
++      return 1;
++}
++
++/*
++ * Find lo/hi client ports (if any) in transport header
++ * In:
++ *   ptcp, tcplen = packet
++ *   tranoff, tranlen = buffer to search
++ *
++ * Out:
++ *   pport_lo, pport_hi = lo/hi ports (host endian)
++ *
++ * Returns nonzero if any client ports found
++ *
++ * Note: it is valid (and expected) for the client to request multiple
++ * transports, so we need to parse the entire line.
++ */
++static int
++rtsp_parse_transport(char* ptran, uint tranlen,
++                     struct ip_ct_rtsp_expect* prtspexp)
++{
++      int     rc = 0;
++      uint    off = 0;
++      
++      if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++          nf_strncasecmp(ptran, "Transport:", 10) != 0) {
++              pr_info("sanity check failed\n");
++              return 0;
++      }
++      
++      pr_debug("tran='%.*s'\n", (int)tranlen, ptran);
++      off += 10;
++      SKIP_WSPACE(ptran, tranlen, off);
++      
++      /* Transport: tran;field;field=val,tran;field;field=val,... */
++      while (off < tranlen) {
++              const char* pparamend;
++              uint        nextparamoff;
++              
++              pparamend = memchr(ptran+off, ',', tranlen-off);
++              pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++              nextparamoff = pparamend-ptran;
++              
++              while (off < nextparamoff) {
++                      const char* pfieldend;
++                      uint        nextfieldoff;
++                      
++                      pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++                      nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++                 
++                      if (strncmp(ptran+off, "client_port=", 12) == 0) {
++                              u_int16_t   port;
++                              uint        numlen;
++                  
++                              off += 12;
++                              numlen = nf_strtou16(ptran+off, &port);
++                              off += numlen;
++                              if (prtspexp->loport != 0 && prtspexp->loport != port)
++                                      pr_debug("multiple ports found, port %hu ignored\n", port);
++                              else {
++                                      pr_debug("lo port found : %hu\n", port);
++                                      prtspexp->loport = prtspexp->hiport = port;
++                                      if (ptran[off] == '-') {
++                                              off++;
++                                              numlen = nf_strtou16(ptran+off, &port);
++                                              off += numlen;
++                                              prtspexp->pbtype = pb_range;
++                                              prtspexp->hiport = port;
++                                              
++                                              // If we have a range, assume rtp:
++                                              // loport must be even, hiport must be loport+1
++                                              if ((prtspexp->loport & 0x0001) != 0 ||
++                                                  prtspexp->hiport != prtspexp->loport+1) {
++                                                      pr_debug("incorrect range: %hu-%hu, correcting\n",
++                                                             prtspexp->loport, prtspexp->hiport);
++                                                      prtspexp->loport &= 0xfffe;
++                                                      prtspexp->hiport = prtspexp->loport+1;
++                                              }
++                                      } else if (ptran[off] == '/') {
++                                              off++;
++                                              numlen = nf_strtou16(ptran+off, &port);
++                                              off += numlen;
++                                              prtspexp->pbtype = pb_discon;
++                                              prtspexp->hiport = port;
++                                      }
++                                      rc = 1;
++                              }
++                      }
++                      
++                      /*
++                       * Note we don't look for the destination parameter here.
++                       * If we are using NAT, the NAT module will handle it.  If not,
++                       * and the client is sending packets elsewhere, the expectation
++                       * will quietly time out.
++                       */
++                      
++                      off = nextfieldoff;
++              }
++              
++              off = nextparamoff;
++      }
++      
++      return rc;
++}
++
++void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp)
++{
++              typeof(nf_nat_rtsp_hook_expectfn) nf_nat_rtsp_expectfn;
++              nf_nat_rtsp_expectfn = rcu_dereference(nf_nat_rtsp_hook_expectfn);
++    if(nf_nat_rtsp_expectfn && ct->master->status & IPS_NAT_MASK) {
++        nf_nat_rtsp_expectfn(ct,exp);
++    }
++}
++
++/*** conntrack functions ***/
++
++/* outbound packet: client->server */
++
++static inline int
++help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
++                struct nf_conn *ct, enum ip_conntrack_info ctinfo)
++{
++      struct ip_ct_rtsp_expect expinfo;
++      
++      int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
++      //struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
++      //uint    tcplen = pktlen - iph->ihl * 4;
++      char*   pdata = rb_ptr;
++      //uint    datalen = tcplen - tcph->doff * 4;
++      uint    dataoff = 0;
++      int ret = NF_ACCEPT;
++      
++      struct nf_conntrack_expect *exp;
++      
++      __be16 be_loport;
++      
++      typeof(nf_nat_rtsp_hook) nf_nat_rtsp;
++
++      memset(&expinfo, 0, sizeof(expinfo));
++      
++      while (dataoff < datalen) {
++              uint    cmdoff = dataoff;
++              uint    hdrsoff = 0;
++              uint    hdrslen = 0;
++              uint    cseqoff = 0;
++              uint    cseqlen = 0;
++              uint    transoff = 0;
++              uint    translen = 0;
++              uint    off;
++              
++              if (!rtsp_parse_message(pdata, datalen, &dataoff,
++                                      &hdrsoff, &hdrslen,
++                                      &cseqoff, &cseqlen,
++                                      &transoff, &translen))
++                      break;      /* not a valid message */
++              
++              if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
++                      continue;   /* not a SETUP message */
++              pr_debug("found a setup message\n");
++
++              off = 0;
++              if(translen) {
++                      rtsp_parse_transport(pdata+transoff, translen, &expinfo);
++              }
++
++              if (expinfo.loport == 0) {
++                      pr_debug("no udp transports found\n");
++                      continue;   /* no udp transports found */
++              }
++
++              pr_debug("udp transport found, ports=(%d,%hu,%hu)\n",
++                     (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);
++
++              exp = nf_ct_expect_alloc(ct);
++              if (!exp) {
++                      ret = NF_DROP;
++                      goto out;
++              }
++
++              be_loport = htons(expinfo.loport);
++
++              nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
++                      &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3,
++                      IPPROTO_UDP, NULL, &be_loport); 
++
++              exp->master = ct;
++
++              exp->expectfn = expected;
++              exp->flags = 0;
++
++              if (expinfo.pbtype == pb_range) {
++                      pr_debug("Changing expectation mask to handle multiple ports\n");
++                      //exp->mask.dst.u.udp.port  = 0xfffe;
++              }
++
++              pr_debug("expect_related %pI4:%u-%pI4:%u\n",
++                     &exp->tuple.src.u3.ip,
++                     ntohs(exp->tuple.src.u.udp.port),
++                     &exp->tuple.dst.u3.ip,
++                     ntohs(exp->tuple.dst.u.udp.port));
++
++              nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook);
++              if (nf_nat_rtsp && ct->status & IPS_NAT_MASK)
++                      /* pass the request off to the nat helper */
++                      ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp);
++              else if (nf_ct_expect_related(exp) != 0) {
++                      pr_info("nf_conntrack_expect_related failed\n");
++                      ret  = NF_DROP;
++              }
++              nf_ct_expect_put(exp);
++              goto out;
++      }
++out:
++
++      return ret;
++}
++
++
++static inline int
++help_in(struct sk_buff *skb, size_t pktlen,
++ struct nf_conn* ct, enum ip_conntrack_info ctinfo)
++{
++ return NF_ACCEPT;
++}
++
++static int help(struct sk_buff *skb, unsigned int protoff,
++              struct nf_conn *ct, enum ip_conntrack_info ctinfo) 
++{
++      struct tcphdr _tcph, *th;
++      unsigned int dataoff, datalen;
++      char *rb_ptr;
++      int ret = NF_DROP;
++
++      /* Until there's been traffic both ways, don't look in packets. */
++      if (ctinfo != IP_CT_ESTABLISHED && 
++          ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++              pr_debug("conntrackinfo = %u\n", ctinfo);
++              return NF_ACCEPT;
++      } 
++
++      /* Not whole TCP header? */
++      th = skb_header_pointer(skb,protoff, sizeof(_tcph), &_tcph);
++
++      if (!th)
++              return NF_ACCEPT;
++   
++      /* No data ? */
++      dataoff = protoff + th->doff*4;
++      datalen = skb->len - dataoff;
++      if (dataoff >= skb->len)
++              return NF_ACCEPT;
++
++      spin_lock_bh(&rtsp_buffer_lock);
++      rb_ptr = skb_header_pointer(skb, dataoff,
++                                  skb->len - dataoff, rtsp_buffer);
++      BUG_ON(rb_ptr == NULL);
++
++#if 0
++      /* Checksum invalid?  Ignore. */
++      /* FIXME: Source route IP option packets --RR */
++      if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++                       csum_partial((char*)tcph, tcplen, 0)))
++      {
++              DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++                     tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++              return NF_ACCEPT;
++      }
++#endif
++
++      switch (CTINFO2DIR(ctinfo)) {
++      case IP_CT_DIR_ORIGINAL:
++              ret = help_out(skb, rb_ptr, datalen, ct, ctinfo);
++              break;
++      case IP_CT_DIR_REPLY:
++              pr_debug("IP_CT_DIR_REPLY\n");
++              /* inbound packet: server->client */
++              ret = NF_ACCEPT;
++              break;
++      }
++
++      spin_unlock_bh(&rtsp_buffer_lock);
++
++      return ret;
++}
++
++static struct nf_conntrack_helper rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++      int i;
++      for (i = 0; i < num_ports; i++) {
++              pr_debug("unregistering port %d\n", ports[i]);
++              nf_conntrack_helper_unregister(&rtsp_helpers[i]);
++      }
++      kfree(rtsp_buffer);
++}
++
++static int __init
++init(void)
++{
++      int i, ret;
++      struct nf_conntrack_helper *hlpr;
++      char *tmpname;
++
++      printk("nf_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++      if (max_outstanding < 1) {
++              printk("nf_conntrack_rtsp: max_outstanding must be a positive integer\n");
++              return -EBUSY;
++      }
++      if (setup_timeout < 0) {
++              printk("nf_conntrack_rtsp: setup_timeout must be a positive integer\n");
++              return -EBUSY;
++      }
++
++  rtsp_exp_policy.max_expected = max_outstanding;
++  rtsp_exp_policy.timeout = setup_timeout;
++      
++      rtsp_buffer = kmalloc(65536, GFP_KERNEL);
++      if (!rtsp_buffer) 
++              return -ENOMEM;
++
++      /* If no port given, default to standard rtsp port */
++      if (ports[0] == 0) {
++              ports[0] = RTSP_PORT;
++      }
++
++      for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++              hlpr = &rtsp_helpers[i];
++              memset(hlpr, 0, sizeof(struct nf_conntrack_helper));
++              hlpr->tuple.src.l3num = AF_INET;
++              hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++              hlpr->tuple.dst.protonum = IPPROTO_TCP;
++              //hlpr->mask.src.u.tcp.port = 0xFFFF;
++              //hlpr->mask.dst.protonum = 0xFF;
++              hlpr->expect_policy = &rtsp_exp_policy;
++              hlpr->me = THIS_MODULE;
++              hlpr->help = help;
++
++              tmpname = &rtsp_names[i][0];
++              if (ports[i] == RTSP_PORT) {
++                      sprintf(tmpname, "rtsp");
++              } else {
++                      sprintf(tmpname, "rtsp-%d", i);
++              }
++              hlpr->name = tmpname;
++
++              pr_debug("port #%d: %d\n", i, ports[i]);
++
++              ret = nf_conntrack_helper_register(hlpr);
++
++              if (ret) {
++                      printk("nf_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
++                      fini();
++                      return -EBUSY;
++              }
++              num_ports++;
++      }
++      return 0;
++}
++
++module_init(init);
++module_exit(fini);
++
++EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn);
++
+--- /dev/null
++++ b/extensions/rtsp/nf_conntrack_rtsp.h
+@@ -0,0 +1,63 @@
++/*
++ * RTSP extension for IP connection tracking.
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ * based on ip_conntrack_irc.h
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ */
++#ifndef _IP_CONNTRACK_RTSP_H
++#define _IP_CONNTRACK_RTSP_H
++
++//#define IP_NF_RTSP_DEBUG 1
++#define IP_NF_RTSP_VERSION "0.6.21"
++
++#ifdef __KERNEL__
++/* port block types */
++typedef enum {
++    pb_single,  /* client_port=x */
++    pb_range,   /* client_port=x-y */
++    pb_discon   /* client_port=x/y (rtspbis) */
++} portblock_t;
++
++/* We record seq number and length of rtsp headers here, all in host order. */
++
++/*
++ * This structure is per expected connection.  It is a member of struct
++ * ip_conntrack_expect.  The TCP SEQ for the conntrack expect is stored
++ * there and we are expected to only store the length of the data which
++ * needs replaced.  If a packet contains multiple RTSP messages, we create
++ * one expected connection per message.
++ *
++ * We use these variables to mark the entire header block.  This may seem
++ * like overkill, but the nature of RTSP requires it.  A header may appear
++ * multiple times in a message.  We must treat two Transport headers the
++ * same as one Transport header with two entries.
++ */
++struct ip_ct_rtsp_expect
++{
++    u_int32_t   len;        /* length of header block */
++    portblock_t pbtype;     /* Type of port block that was requested */
++    u_int16_t   loport;     /* Port that was requested, low or first */
++    u_int16_t   hiport;     /* Port that was requested, high or second */
++#if 0
++    uint        method;     /* RTSP method */
++    uint        cseq;       /* CSeq from request */
++#endif
++};
++
++extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
++                               enum ip_conntrack_info ctinfo,
++                               unsigned int matchoff, unsigned int matchlen,
++                               struct ip_ct_rtsp_expect *prtspexp,
++                               struct nf_conntrack_expect *exp);
++
++extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
++
++#define RTSP_PORT   554
++
++#endif /* __KERNEL__ */
++
++#endif /* _IP_CONNTRACK_RTSP_H */
+--- /dev/null
++++ b/extensions/rtsp/nf_nat_rtsp.c
+@@ -0,0 +1,491 @@
++/*
++ * RTSP extension for TCP NAT alteration
++ * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ * based on ip_nat_irc.c
++ *
++ *      This program is free software; you can redistribute it and/or
++ *      modify it under the terms of the GNU General Public License
++ *      as published by the Free Software Foundation; either version
++ *      2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ *      insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *                           stunaddr=<address>
++ *                           destaction=[auto|strip|none]
++ *
++ * If no ports are specified, the default will be port 554 only.
++ *
++ * stunaddr specifies the address used to detect that a client is using STUN.
++ * If this address is seen in the destination parameter, it is assumed that
++ * the client has already punched a UDP hole in the firewall, so we don't
++ * mangle the client_port.  If none is specified, it is autodetected.  It
++ * only needs to be set if you have multiple levels of NAT.  It should be
++ * set to the external address that the STUN clients detect.  Note that in
++ * this case, it will not be possible for clients to use UDP with servers
++ * between the NATs.
++ *
++ * If no destaction is specified, auto is used.
++ *   destaction=auto:  strip destination parameter if it is not stunaddr.
++ *   destaction=strip: always strip destination parameter (not recommended).
++ *   destaction=none:  do not touch destination parameter (not recommended).
++ */
++
++#include <linux/module.h>
++#include <net/tcp.h>
++#include <net/netfilter/nf_nat_helper.h>
++#include <net/netfilter/nf_nat_rule.h>
++#include "nf_conntrack_rtsp.h"
++#include <net/netfilter/nf_conntrack_expect.h>
++
++#include <linux/inet.h>
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#include "netfilter_helpers.h"
++#define NF_NEED_MIME_NEXTLINE
++#include "netfilter_mime.h"
++
++#include "../compat_xtables.h"
++
++#define MAX_PORTS       8
++#define DSTACT_AUTO     0
++#define DSTACT_STRIP    1
++#define DSTACT_NONE     2
++
++static char*    stunaddr = NULL;
++static char*    destaction = NULL;
++
++static u_int32_t extip = 0;
++static int       dstact = 0;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
++MODULE_DESCRIPTION("RTSP network address translation module");
++MODULE_LICENSE("GPL");
++module_param(stunaddr, charp, 0644);
++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
++module_param(destaction, charp, 0644);
++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*** helper functions ***/
++
++static void
++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
++{
++    struct iphdr*   iph  = ip_hdr(skb);
++    struct tcphdr*  tcph = (void *)iph + ip_hdrlen(skb);
++
++    *pptcpdata = (char*)tcph +  tcph->doff*4;
++    *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata;
++}
++
++/*** nat functions ***/
++
++/*
++ * Mangle the "Transport:" header:
++ *   - Replace all occurences of "client_port=<spec>"
++ *   - Handle destination parameter
++ *
++ * In:
++ *   ct, ctinfo = conntrack context
++ *   skb        = packet
++ *   tranoff    = Transport header offset from TCP data
++ *   tranlen    = Transport header length (incl. CRLF)
++ *   rport_lo   = replacement low  port (host endian)
++ *   rport_hi   = replacement high port (host endian)
++ *
++ * Returns packet size difference.
++ *
++ * Assumes that a complete transport header is present, ending with CR or LF
++ */
++static int
++rtsp_mangle_tran(enum ip_conntrack_info ctinfo,
++                 struct nf_conntrack_expect* exp,
++                                                               struct ip_ct_rtsp_expect* prtspexp,
++                 struct sk_buff* skb, uint tranoff, uint tranlen)
++{
++    char*       ptcp;
++    uint        tcplen;
++    char*       ptran;
++    char        rbuf1[16];      /* Replacement buffer (one port) */
++    uint        rbuf1len;       /* Replacement len (one port) */
++    char        rbufa[16];      /* Replacement buffer (all ports) */
++    uint        rbufalen;       /* Replacement len (all ports) */
++    u_int32_t   newip;
++    u_int16_t   loport, hiport;
++    uint        off = 0;
++    uint        diff;           /* Number of bytes we removed */
++
++    struct nf_conn *ct = exp->master;
++    struct nf_conntrack_tuple *t;
++
++    char    szextaddr[15+1];
++    uint    extaddrlen;
++    int     is_stun;
++
++    get_skb_tcpdata(skb, &ptcp, &tcplen);
++    ptran = ptcp+tranoff;
++
++    if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++        tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++        nf_strncasecmp(ptran, "Transport:", 10) != 0)
++    {
++        pr_info("sanity check failed\n");
++        return 0;
++    }
++    off += 10;
++    SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
++    t = &exp->tuple;
++    t->dst.u3.ip = newip;
++
++    extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip)
++                       : sprintf(szextaddr, "%pI4", &newip);
++    pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++
++    rbuf1len = rbufalen = 0;
++    switch (prtspexp->pbtype)
++    {
++    case pb_single:
++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++        {
++            t->dst.u.udp.port = htons(loport);
++            if (nf_ct_expect_related(exp) == 0)
++            {
++                pr_debug("using port %hu\n", loport);
++                break;
++            }
++        }
++        if (loport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            rbufalen = sprintf(rbufa, "%hu", loport);
++        }
++        break;
++    case pb_range:
++        for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
++        {
++            t->dst.u.udp.port = htons(loport);
++            if (nf_ct_expect_related(exp) == 0)
++            {
++                hiport = loport + 1; //~exp->mask.dst.u.udp.port;
++                pr_debug("using ports %hu-%hu\n", loport, hiport);
++                break;
++            }
++        }
++        if (loport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
++        }
++        break;
++    case pb_discon:
++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++        {
++            t->dst.u.udp.port = htons(loport);
++            if (nf_ct_expect_related(exp) == 0)
++            {
++                pr_debug("using port %hu (1 of 2)\n", loport);
++                break;
++            }
++        }
++        for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
++        {
++            t->dst.u.udp.port = htons(hiport);
++            if (nf_ct_expect_related(exp) == 0)
++            {
++                pr_debug("using port %hu (2 of 2)\n", hiport);
++                break;
++            }
++        }
++        if (loport != 0 && hiport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            if (hiport == loport+1)
++            {
++                rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++            }
++            else
++            {
++                rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
++            }
++        }
++        break;
++    }
++
++    if (rbuf1len == 0)
++    {
++        return 0;   /* cannot get replacement port(s) */
++    }
++
++    /* Transport: tran;field;field=val,tran;field;field=val,... */
++    while (off < tranlen)
++    {
++        uint        saveoff;
++        const char* pparamend;
++        uint        nextparamoff;
++
++        pparamend = memchr(ptran+off, ',', tranlen-off);
++        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++        nextparamoff = pparamend-ptcp;
++
++        /*
++         * We pass over each param twice.  On the first pass, we look for a
++         * destination= field.  It is handled by the security policy.  If it
++         * is present, allowed, and equal to our external address, we assume
++         * that STUN is being used and we leave the client_port= field alone.
++         */
++        is_stun = 0;
++        saveoff = off;
++        while (off < nextparamoff)
++        {
++            const char* pfieldend;
++            uint        nextfieldoff;
++
++            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++            if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
++            {
++                if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
++                {
++                    is_stun = 1;
++                }
++                if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
++                {
++                    diff = nextfieldoff-off;
++                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++                                                         off, diff, NULL, 0))
++                    {
++                        /* mangle failed, all we can do is bail */
++                      nf_ct_unexpect_related(exp);
++                        return 0;
++                    }
++                    get_skb_tcpdata(skb, &ptcp, &tcplen);
++                    ptran = ptcp+tranoff;
++                    tranlen -= diff;
++                    nextparamoff -= diff;
++                    nextfieldoff -= diff;
++                }
++            }
++
++            off = nextfieldoff;
++        }
++        if (is_stun)
++        {
++            continue;
++        }
++        off = saveoff;
++        while (off < nextparamoff)
++        {
++            const char* pfieldend;
++            uint        nextfieldoff;
++
++            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++            if (strncmp(ptran+off, "client_port=", 12) == 0)
++            {
++                u_int16_t   port;
++                uint        numlen;
++                uint        origoff;
++                uint        origlen;
++                char*       rbuf    = rbuf1;
++                uint        rbuflen = rbuf1len;
++
++                off += 12;
++                origoff = (ptran-ptcp)+off;
++                origlen = 0;
++                numlen = nf_strtou16(ptran+off, &port);
++                off += numlen;
++                origlen += numlen;
++                if (port != prtspexp->loport)
++                {
++                    pr_debug("multiple ports found, port %hu ignored\n", port);
++                }
++                else
++                {
++                    if (ptran[off] == '-' || ptran[off] == '/')
++                    {
++                        off++;
++                        origlen++;
++                        numlen = nf_strtou16(ptran+off, &port);
++                        off += numlen;
++                        origlen += numlen;
++                        rbuf = rbufa;
++                        rbuflen = rbufalen;
++                    }
++
++                    /*
++                     * note we cannot just memcpy() if the sizes are the same.
++                     * the mangle function does skb resizing, checks for a
++                     * cloned skb, and updates the checksums.
++                     *
++                     * parameter 4 below is offset from start of tcp data.
++                     */
++                    diff = origlen-rbuflen;
++                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++                                              origoff, origlen, rbuf, rbuflen))
++                    {
++                        /* mangle failed, all we can do is bail */
++                      nf_ct_unexpect_related(exp);
++                        return 0;
++                    }
++                    get_skb_tcpdata(skb, &ptcp, &tcplen);
++                    ptran = ptcp+tranoff;
++                    tranlen -= diff;
++                    nextparamoff -= diff;
++                    nextfieldoff -= diff;
++                }
++            }
++
++            off = nextfieldoff;
++        }
++
++        off = nextparamoff;
++    }
++
++    return 1;
++}
++
++static uint
++help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
++       unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 
++       struct nf_conntrack_expect* exp)
++{
++    char*   ptcp;
++    uint    tcplen;
++    uint    hdrsoff;
++    uint    hdrslen;
++    uint    lineoff;
++    uint    linelen;
++    uint    off;
++
++    //struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++    //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
++
++    get_skb_tcpdata(skb, &ptcp, &tcplen);
++    hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq);
++    hdrslen = matchlen;
++    off = hdrsoff;
++    pr_debug("NAT rtsp help_out\n");
++
++    while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
++    {
++        if (linelen == 0)
++        {
++            break;
++        }
++        if (off > hdrsoff+hdrslen)
++        {
++            pr_info("!! overrun !!");
++            break;
++        }
++        pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++        if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
++        {
++            uint oldtcplen = tcplen;
++          pr_debug("hdr: Transport\n");
++            if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen))
++            {
++              pr_debug("hdr: Transport mangle failed");
++                break;
++            }
++            get_skb_tcpdata(skb, &ptcp, &tcplen);
++            hdrslen -= (oldtcplen-tcplen);
++            off -= (oldtcplen-tcplen);
++            lineoff -= (oldtcplen-tcplen);
++            linelen -= (oldtcplen-tcplen);
++            pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++        }
++    }
++
++    return NF_ACCEPT;
++}
++
++static unsigned int
++help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 
++     unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
++     struct nf_conntrack_expect* exp)
++{
++    int dir = CTINFO2DIR(ctinfo);
++    int rc = NF_ACCEPT;
++
++    switch (dir)
++    {
++    case IP_CT_DIR_ORIGINAL:
++        rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp);
++        break;
++    case IP_CT_DIR_REPLY:
++      pr_debug("unmangle ! %u\n", ctinfo);
++      /* XXX: unmangle */
++      rc = NF_ACCEPT;
++        break;
++    }
++    //UNLOCK_BH(&ip_rtsp_lock);
++
++    return rc;
++}
++
++static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
++{
++    struct nf_nat_ipv4_multi_range_compat mr;
++    u_int32_t newdstip, newsrcip, newip;
++
++    struct nf_conn *master = ct->master;
++
++    newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
++    newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
++    //FIXME (how to port that ?)
++    //code from 2.4 : newip = (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC) ? newsrcip : newdstip;
++    newip = newdstip;
++
++    pr_debug("newsrcip=%pI4, newdstip=%pI4, newip=%pI4\n",
++           &newsrcip, &newdstip, &newip);
++
++    mr.rangesize = 1;
++    // We don't want to manip the per-protocol, just the IPs. 
++    mr.range[0].flags = NF_NAT_RANGE_MAP_IPS;
++    mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++    nf_nat_setup_info(ct, &mr.range[0], NF_NAT_MANIP_DST);
++}
++
++
++static void __exit fini(void)
++{
++      nf_nat_rtsp_hook = NULL;
++        nf_nat_rtsp_hook_expectfn = NULL;
++      synchronize_net();
++}
++
++static int __init init(void)
++{
++      printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++      BUG_ON(nf_nat_rtsp_hook);
++      nf_nat_rtsp_hook = help;
++        nf_nat_rtsp_hook_expectfn = &expected;
++
++      if (stunaddr != NULL)
++              extip = in_aton(stunaddr);
++
++      if (destaction != NULL) {
++              if (strcmp(destaction, "auto") == 0)
++                      dstact = DSTACT_AUTO;
++
++              if (strcmp(destaction, "strip") == 0)
++                      dstact = DSTACT_STRIP;
++
++              if (strcmp(destaction, "none") == 0)
++                      dstact = DSTACT_NONE;
++      }
++
++      return 0;
++}
++
++module_init(init);
++module_exit(fini);
+--- a/extensions/Kbuild
++++ b/extensions/Kbuild
+@@ -35,6 +35,7 @@ obj-${build_lscan}       += xt_lscan.o
+ obj-${build_pknock}      += pknock/
+ obj-${build_psd}         += xt_psd.o
+ obj-${build_quota2}      += xt_quota2.o
++obj-${build_rtsp}        += rtsp/
+ -include ${M}/*.Kbuild
+ -include ${M}/Kbuild.*
+--- a/mconfig
++++ b/mconfig
+@@ -26,3 +26,4 @@ build_lscan=m
+ build_pknock=m
+ build_psd=m
+ build_quota2=m
++build_rtsp=m
diff --git a/package/network/utils/xtables-addons/patches-1.x/101-rtsp-linux-3.6-compat.patch b/package/network/utils/xtables-addons/patches-1.x/101-rtsp-linux-3.6-compat.patch
new file mode 100644 (file)
index 0000000..b8e08b3
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/extensions/rtsp/nf_conntrack_rtsp.c
++++ b/extensions/rtsp/nf_conntrack_rtsp.c
+@@ -28,6 +28,7 @@
+  *                    - Port to new NF API
+  */
++#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/netfilter.h>
+ #include <linux/ip.h>
+@@ -496,7 +497,11 @@ init(void)
+               } else {
+                       sprintf(tmpname, "rtsp-%d", i);
+               }
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++              strncpy(hlpr->name, tmpname, sizeof(hlpr->name));
++#else
+               hlpr->name = tmpname;
++#endif
+               pr_debug("port #%d: %d\n", i, ports[i]);
diff --git a/package/network/utils/xtables-addons/patches-1.x/200-add-lua-packetscript.patch b/package/network/utils/xtables-addons/patches-1.x/200-add-lua-packetscript.patch
new file mode 100644 (file)
index 0000000..1717bf5
--- /dev/null
@@ -0,0 +1,18230 @@
+--- /dev/null
++++ b/extensions/LUA/byte_array.c
+@@ -0,0 +1,145 @@
++/*
++ *    Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *    by Andre Graf <andre@dergraf.org>
++ *
++ *    This program is free software; you can redistribute it and/or modify
++ *    it under the terms of the GNU General Public License as published by
++ *    the Free Software Foundation; either version 2 of the License, or
++ *    (at your option) any later version.
++ *
++ *    This program is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *    GNU General Public License for more details.
++ *
++ *    You should have received a copy of the GNU General Public License
++ *    along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++#include "controller.h"
++
++/* Initialization helper function. This function should be used whenever
++ * a new byte array need to be initialized. Depending on the arguments it
++ * initializes the array in a different way. Have a look at the inline
++ * comments */
++lua_packet_segment * init_byte_array(lua_State *L, unsigned char * start, int length, int do_copy)
++{
++      lua_packet_segment *array;
++
++      if (length < 0)
++              luaL_error(L, "init_byte_array, requested size < 0");
++
++      if (start && do_copy) {
++              /* we have a start address where we copy from */
++              array = lua_newuserdata(L, sizeof(lua_packet_segment) + length);
++              array->start = (unsigned char *)array + sizeof(lua_packet_segment); /* aligning pointer */
++              memcpy(array->start, start, length);
++      }else if (start && !do_copy) {
++              /* just link the start pointer, in this case you have to free the memory yourself */
++              array = lua_newuserdata(L, sizeof(lua_packet_segment));
++              array->start = start;
++      }else{
++              /* create an empty array, fully managed by Lua */
++              array = lua_newuserdata(L, sizeof(lua_packet_segment) + length);
++              array->start = (unsigned char *)array + sizeof(lua_packet_segment); /* aligning pointer */
++              memset(array->start, 0, length);
++      }
++
++      array->length = length;
++      array->offset = 0;
++      array->changes = NULL;
++
++      luaL_getmetatable(L, LUA_BYTE_ARRAY);
++      lua_setmetatable(L, -2);
++
++      return array;
++}
++
++
++
++/* LUA_API: get one byte of the given byte array 
++ * access-pattern: array[<index>] */
++static int32_t get_byte_array(lua_State *L)
++{
++      lua_packet_segment * array = checkbytearray(L, 1);
++      int32_t index = luaL_checkinteger(L, 2); /* array starts with index 0 (not 1 as usual in Lua) */
++
++      luaL_argcheck(L, 0 <= index && index < array->length, 1, "index out of range");
++      lua_pushinteger(L, (array->start + array->offset)[index]);
++
++      return 1;
++}
++
++/* LUA_API: set one byte of the given byte array
++ * access-pattern: array[<index>]= 0xFF */
++static int32_t set_byte_array(lua_State *L)
++{
++      lua_packet_segment * array = checkbytearray(L, 1);
++      uint8_t byte;
++      int32_t index = luaL_checkinteger(L, 2);    /* array starts with index 0 (not 1 as usual in Lua) */
++      int32_t val = luaL_checkinteger(L, 3);
++      uint32_t  nob = 1 << CHAR_BIT;               /* we should use something like 1 << CHAR_BIT */
++
++      luaL_argcheck(L, 0 <= index && index < array->length, 1, "index out of range");
++      luaL_argcheck(L, 0 <= val && val < nob, 2, "cannot cast value to char");
++
++      byte = (uint8_t)val;
++
++      (array->start + array->offset)[index] = byte;
++
++      return 0;
++}
++
++/* LUA_API: get size of the given byte array
++ * access-pattern: #array (__length meta-method) */
++static int32_t get_byte_array_size(lua_State *L)
++{
++      lua_packet_segment * array = checkbytearray(L, 1);
++
++      lua_pushnumber(L, array->length);
++
++      return 1;
++}
++
++
++/* LUA_API: converts a given byte array to a string. 
++ * access-pattern: implicit through functions calling the
++ * __to_string() metamethod , e.g. print32_t */
++static int32_t byte_array_to_string(lua_State *L)
++{
++      lua_packet_segment * array = checkbytearray(L, 1);
++      uint8_t buf[(array->length * 3) + 255];
++      uint8_t hexval[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
++      char res[255 + (array->length * 3)]; /* make sure the buffer is big enough*/
++      int32_t i, n;
++      uint8_t *ptr = array->start + array->offset;
++
++      for (i = 0; i < array->length; i++) {
++              buf[i * 3] = hexval[(ptr[i] >> 4) & 0xF];
++              buf[(i * 3) + 1] = hexval[ptr[i] & 0x0F];
++              buf[(i * 3) + 2] = ' '; /* seperator */
++      }
++
++      buf[array->length * 3] = '\0';
++      n = sprintf(res, "byte_array: length: %d  value: %s", array->length, buf);
++
++      lua_pushlstring(L, res, n);
++
++      return 1;
++}
++
++static const struct luaL_Reg bytearray_lib_m [] = {
++      { "__len",      get_byte_array_size  },
++      { "__newindex", set_byte_array       },
++      { "__index",    get_byte_array       },
++      { "__tostring", byte_array_to_string },
++      { NULL,         NULL                 }
++};
++
++void luaopen_bytearraylib(lua_State *L)
++{
++      luaL_newmetatable(L, LUA_BYTE_ARRAY);
++      luaL_register(L, NULL, bytearray_lib_m);
++      lua_pop(L, 1);
++}
++
++
+--- /dev/null
++++ b/extensions/LUA/controller.c
+@@ -0,0 +1,604 @@
++/*
++ *    Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *    by Andre Graf <andre@dergraf.org>
++ *
++ *    This program is free software; you can redistribute it and/or modify
++ *    it under the terms of the GNU General Public License as published by
++ *    the Free Software Foundation; either version 2 of the License, or
++ *    (at your option) any later version.
++ *
++ *    This program is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *    GNU General Public License for more details.
++ *
++ *    You should have received a copy of the GNU General Public License
++ *    along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#if defined(__KERNEL__)
++      #include <linux/mm.h>
++#endif
++#include "controller.h"
++
++/* the array 'supported_protocols' holds all pointers to the 
++ * static and dynamic protocol buffers. It is filled by the 
++ * call to register_protbuf */
++static struct protocol_buf * supported_protocols[MAX_NR_OF_PROTOCOLS];
++
++/* C_API: the function 'get_protocol_buf' returns the pointer 
++ * to the protocol buffer of a given protocol id. */
++struct protocol_buf * get_protocol_buf(uint32_t  protocol_id)
++{
++      return (struct protocol_buf *)supported_protocols[protocol_id];
++}
++
++
++/* LUA_INT: the function 'gc_packet_segment' is triggered by the 
++ * garbage collector whenever a userdata annotated with one of 
++ * the protocol buffer metatable should be collected. */
++static int32_t gc_packet_segment(lua_State *L)
++{
++      lua_packet_segment * seg = (lua_packet_segment *)lua_touserdata(L, 1);
++      if (seg && seg->changes) {
++              seg->changes->ref_count--;
++              if (seg->changes->ref_count <= 0) {
++                      kfree(seg->changes->field_length_changes);
++                      kfree(seg->changes->field_offset_changes);
++                      kfree(seg->changes);
++                      seg->changes = NULL;
++              }
++      }
++      return 0;
++}
++
++
++/* LUA_API: the function 'set_raw' is used to set the bytes of a segment 
++ * in 'raw' mode. The function is per default available in each protocol 
++ * buffer until it gets overridden by a specific setter function inside 
++ * a protocol buffer.
++ * 
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ * 2. int32_t byte_value
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return: void
++ */
++static int32_t set_raw(lua_State *L)
++{
++      int32_t i;
++      uint32_t  nob;
++      uint8_t byte;
++      uint8_t *ptr;
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++      int32_t val = luaL_checkinteger(L, 2);
++
++      nob = 1 << CHAR_BIT;
++
++      luaL_argcheck(L, 0 <= val && val < nob, 2, "cannot cast value to char");
++
++      byte = (uint8_t)val;
++      ptr = seg->start + seg->offset;
++
++      for (i = 0; i < seg->length; i++)
++              ptr[i] = byte;
++
++      return 0;
++}
++
++/* LUA_API: the function 'get_raw' is used to get the bytes of a segment 
++ * in 'raw' mode. The function is per default available in each protocol 
++ * buffer until it gets overridden by a specific getter function inside 
++ * a protocol buffer.
++ *
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ * 2. uint32_t  offset
++ * 3. uint32_t  length 
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return: 
++ * the byte array representing the given array
++ */
++static int32_t get_raw(lua_State *L)
++{
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++      init_byte_array(L, seg->start + seg->offset,  seg->length, 1);
++
++      return 1;
++}
++/* LUA_API: The function 'get_segment' is used to get a new segment in 'raw' mode. 
++ * Typically this function is applied on another raw segment in order 
++ * to extract a part of the segment as new segment.
++ *
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ * 2.  uint32_t  offset, this indicates where to start the new segment, see e.g below.
++ * 3.  uint32_t  length, this indicates the size of the new segment
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  A lua_packet_segment annotated with the according metatable or False in
++ *     case the input data is not valid
++ *
++ * Example:
++ *
++ * +------------------------+---------------------------------------+
++ * | function call          | resulting lua_packet_segment          |
++ * +========================+===+===+===+===+===+===+===+===+===+===+
++ * | seg = packet:raw(0,10) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
++ * +------------------------+---+---+---+---+---+---+---+---+---+---+
++ * | 1st_half = seg:raw(0,5)| 0 | 1 | 2 | 3 | 4 |                   |
++ * +------------------------+---+---+---+---+---+---+---+---+---+---+
++ * | 2nd_half = seg:raw(5,5)|                   | 5 | 6 | 7 | 8 | 9 |
++ * +------------------------+-------------------+---+---+---+---+---+
++ */
++static int32_t get_segment(lua_State *L)
++{
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++      uint32_t  offset = luaL_checkinteger(L, 2);
++      uint32_t  length = luaL_checkinteger(L, 3);
++      lua_packet_segment * new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++
++      new->start = seg->start;
++      new->offset = seg->offset + offset;
++      new->changes = NULL;
++      /* we allow a seg->length == 0 , this enables processing packets where the packetsize is not fixed (0 = not fixed)*/
++      if (seg->length != 0 && length > seg->length) {
++              lua_pushboolean(L, 0);
++              return 1;
++      }
++
++      new->length = length;
++      luaL_getmetatable(L, prot_buf->name);
++      lua_setmetatable(L, -2);
++
++      return 1;
++}
++
++/* LUA_API: the function 'get_segment_size' is used to get the size of a segment.
++ * 
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  Size as lua_Number
++ */
++static int32_t get_segment_size(lua_State *L)
++{
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++      lua_pushnumber(L, seg->length);
++      return 1;
++}
++
++/* LUA_API: the function 'get_segment_offset' is used to get the real offset 
++ * of a segment. This function returns the offset of the segment to the start
++ * of the buffer. This means the following
++ *     seg1 = packet:raw(2,10)
++ *     seg2 = seg1:raw(3,5)
++ *   offset = seg2:get_offset()
++ *
++ * will give an offset of 5, since the seg1 starts at offset 2, and seg2 starts
++ * at offset (seg1:get_offset() + 3).
++ * 
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index, not used in this function
++ *
++ * Return:
++ * 1.  Offset as lua_Number
++ */
++static int32_t get_segment_offset(lua_State *L)
++{
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++
++      lua_pushnumber(L, seg->offset);
++      return 1;
++}
++
++/* LUA_API: overwrites the __tostring function of a lua_packet_segment.
++ * this will print32_t a nicely formated string, including length,
++ * offset and name of the protocol buffer.
++ *
++ * Parameters:
++ * 1. lua_packet_segment (implicit)
++ *
++ * Returns:
++ * 1. the representing string
++ */
++static int32_t packet_segment_tostring(lua_State *L)
++{
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      lua_packet_segment * seg = checkpacketseg(L, 1, prot_buf->name);
++      int32_t n;
++      char buf[128];
++
++      n = sprintf(buf, "type: %s, offset: %d, length: %d", prot_buf->name, seg->offset, seg->length);
++      lua_pushlstring(L, buf, n);
++
++      return 1;
++}
++
++
++static const struct luaL_Reg seg_access_functions [] = {
++      { "set",        set_raw                 },
++      { "get",        get_raw                 },
++      { "raw",        get_segment             },
++      { "get_offset", get_segment_offset      },
++      { "get_size",   get_segment_size        },
++      { "to_bytes",   get_raw                 },
++      { "__tostring", packet_segment_tostring },
++      { "__gc",       gc_packet_segment       },
++      { NULL,         NULL                    }
++};
++
++/* C_API: the function 'get_metatable_from_protocol_type' is a helper
++ * used in controller.c as well as it may find usage in the static 
++ * protocol buffers and byte array implementation. */
++void get_metatable_from_protocol_type(lua_State *L, int32_t type)
++{
++      char * table;
++      lua_getglobal(L, SUPPORTED_PROTOCOL_TABLE);
++      lua_rawgeti(L, -1, type);
++      table = (char *)luaL_checkstring(L, -1);
++      lua_pop(L, 2); /* pop the table SUPPORTED_PROTOCOL_TABLE and the string pushed by lua_gettable */
++      luaL_getmetatable(L, table);
++      return;
++}
++
++/* C_INT: the function 'payload_contains_protocol' is used internally. 
++ * Depending if static or dynamic protocol buffer it calls the right
++ * validation function. */
++static int32_t payload_contains_protocol(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment *seg, uint32_t  prot_type)
++{
++      if (prot_buf->is_dynamic)
++              return has_protocol_dynamic(L, prot_buf, seg, prot_type);
++      else
++              return prot_buf->has_protocol(L, prot_buf, seg, prot_type);
++}
++
++/* C_INT: the function 'protocol_get_field_changes' is used interally. 
++ * It requests the field_changes struct calling the protocol buffers
++ * 'get_field_changes' function. This funciton is called, whenever
++ * the payload field with a given protocol type is requested inside 
++ * the function 'get_protocol_field' */
++static struct field_changes * protocol_get_field_changes(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg)
++{
++      struct field_changes * changes = NULL;
++
++      if (prot_buf->get_field_changes) {
++              if (prot_buf->is_dynamic)
++                      changes = get_field_changes_dynamic(L, prot_buf, seg);
++              else
++                      changes = prot_buf->get_field_changes(L, seg);
++               /* is already 1 when set by helper 'get_allocated_field_changes,
++                * since not every prot_buf may use this function we enforce it. */
++              changes->ref_count = 1;
++      }
++      return changes;
++}
++
++/* C_INT: the function 'get_field_offset_in_bytes' wrapps the logic of 
++ * calculating the new length with considering the optional field_changes. */
++static int32_t get_field_offset_in_bytes(struct protocol_field * field, lua_packet_segment * seg, int32_t field_index)
++{
++      uint32_t  nr_of_bits, nr_of_bytes, field_offset;
++
++      field_offset = field->offset;
++      /* do we need to manipulate the default values stored inside the protocol buffer ?? */
++      if (seg->changes)
++              field_offset += seg->changes->field_offset_changes[field_index];
++      /* how many bits remain */
++      nr_of_bits = field_offset & (CHAR_BIT - 1);
++      /* assuming CHAR_BIT == 2 ^ 3 */
++      nr_of_bytes = (field_offset - nr_of_bits) >> 3;
++
++      return seg->offset + nr_of_bytes;
++}
++
++/* C_INT: the function 'get_field_length_in_bytes' wrapps the logic of 
++ * calculating the new offset with considering the optional field_changes. */
++static int32_t get_field_length_in_bytes(struct protocol_field * field, lua_packet_segment * seg, int32_t field_index)
++{
++      uint32_t  nr_of_bits, nr_of_bytes, field_length;
++
++      field_length = field->length;
++      /* if the field length is smaller than 1 byte, we take the size of one byte
++       * we treat the case where field_length == 0 in a special way ...*/
++      if (field_length < CHAR_BIT && field_length > 0)
++              field_length = CHAR_BIT;
++
++      /* do we need to manipulate the default values stored inside the protocol buffer ?? */
++      if (seg->changes)
++              field_length += seg->changes->field_length_changes[field_index];
++      /* how many bits remain */
++      nr_of_bits = field_length & (CHAR_BIT - 1);
++      /* assuming CHAR_BIT == 2 ^ 3 */
++      nr_of_bytes = (field_length - nr_of_bits) >> 3;
++      return nr_of_bytes;
++}
++
++/* C_INT: the function 'initialize_field_getter_and_setter' initializes 
++ * the setter and getter function of the field, considering the optional
++ * field manipulator functions defined inside the protocol buffers. */
++static void initialize_field_getter_and_setter(lua_State *L, struct protocol_buf *prot_buf, int32_t field_index)
++{
++      /* lets check if there is a metatable on top of the stack */
++      struct protocol_field * f = (struct protocol_field *)&prot_buf->protocol_fields[field_index];
++
++      if (!lua_istable(L, -1)) luaL_error(L, "cannot initialize getter and setter for field %s->%s, "
++                                          "not a table on top of the stack, is '%s'", prot_buf->name, f->name, lua_typename(L, lua_type(L, -1)));
++
++      /* is there a 'getter' to initialize ? */
++      lua_pushlightuserdata(L, prot_buf);     /* push upvalue 1 */
++      lua_pushinteger(L, field_index);        /* push upvalue 2 */
++      if (f->get) {
++              if (prot_buf->is_dynamic)
++                      lua_pushcclosure(L, field_dynamic_getter, 2);
++              else
++                      lua_pushcclosure(L, f->get, 2);
++      }else
++              /* there is no specific getter defined - fall back to 'get_raw'  */
++              lua_pushcclosure(L, get_raw, 2);
++       /* set the metatable field 'get' */
++      lua_setfield(L, -2, "get");
++
++      /* is there a 'setter' to initialize ? */
++      lua_pushlightuserdata(L, prot_buf);     /* push upvalue 1 */
++      lua_pushinteger(L, field_index);        /* push upvalue 2 */
++      if (f->set) {
++              if (prot_buf->is_dynamic)
++                      lua_pushcclosure(L, field_dynamic_setter, 2);
++              else
++                      lua_pushcclosure(L, f->set, 2);
++      }else
++              /* there is no specific setter defined - fall back to 'set_raw'  */
++              lua_pushcclosure(L, set_raw, 2);
++       /* set the metatable field 'set' */
++      lua_setfield(L, -2, "set");
++}
++
++/* LUA_API: 'get_protocol_field' is used in Lua as a closure for each field of a protocol
++ * buffer. E.g a call to ip = packet:data(packet_ip) will go to this function,
++ * and trigger the conversion of the raw packet to a ip packet. Each call
++ * to a field function of an IP packet, like ip:daddr() uses this function
++ * to to return the right data. In each case you will end up either with a
++ * new packet segment (annotated with the proper metatable) or a boolean
++ * value (False) if something went wrong. In the case everything went fine,
++ * the newly created lua_packet_segment is annotated with the proper
++ * metatable where the fields get and set also contain the specific getter
++ * and setter functions given by the protocol buffer. E.g. the function call
++ * ip:daddr():get() or ip:daddr():set(...) will call the proper function
++ * defined inside the corresponding field definition.
++ *
++ * Parameters:
++ * 1.  lua_packet_segment, implicit through object oriented access seg:raw(..)
++ * 2.  type of the protocol buffer, optional, and only used if the accessed
++ *     field is the payload field. If a type is provided for the access of the
++ *     payload field, the function tries to convert the data pointed to by the
++ *     payload field to the given type. To check if such a conversion is
++ *     possible, it calls the function pointed to by the protocol buffer member
++ *     has_protocol. If this function returns True, the conversion takes place.
++ *
++ * Upvalues:
++ * 1.  struct protocol_buf*
++ * 2.  int32_t field index
++ *
++ * Return:
++ * 1.  A lua_packet_segment annotated with the according metatable or False in
++ *     case the input data is not valid
++ */
++static int32_t get_protocol_field(lua_State *L)
++{
++      int32_t prot_type;
++      lua_packet_segment * seg, *new;
++      struct protocol_buf * prot_buf = (struct protocol_buf *)lua_topointer(L, lua_upvalueindex(1));
++      int32_t field_index = lua_tointeger(L, lua_upvalueindex(2));
++      struct protocol_field * field = &prot_buf->protocol_fields[field_index];
++
++      /* get the current packet segment */
++      seg = checkpacketseg(L, 1, prot_buf->name);
++
++      /* initialize the new packet segment */
++      new = (lua_packet_segment *)lua_newuserdata(L, sizeof(lua_packet_segment));
++      new->start = seg->start;         /* the start is unchanged */
++      new->offset = get_field_offset_in_bytes(field, seg, field_index);
++      new->length = get_field_length_in_bytes(field, seg, field_index);
++
++      /* if new->length == 0 then no configuration was done, we guess the size by subtracting the
++       * new offset from the packet length. since the old length is getting initialized by the
++       * netfilter extension this assumption holds for the very last field of the protocol.
++       * this 'feature' should be used by protocol buffers containing a payload, whereas the
++       * payload field is the last field of the buffer. However, at compile-time unknown field
++       * sizes (and offsets) of fields not being placed at the end of the protocol should be
++       * initialized using the 'get_field_changes' hook system. */
++      if (new->length == 0)
++              new->length = (seg->length + seg->offset) - (new->offset);
++               /*
++                               printf("%s->%s:: seg->offset %i, seg->length %i, new->offset %i, new->length %i\n",
++                                               prot_buf->name, field->name, seg->offset, seg->length, new->offset, new->length);
++                */
++      /* special care for packet payload requests */
++      if (prot_buf->payload_field != NULL && strcmp(prot_buf->payload_field, field->name) == 0) {
++              /* we know the payload field is requested */
++              /* the requested payload can be delivered either as a common segment or as
++               * an other packet type, such a conversion needs an extra protocol parameter
++               * ... so lets check */
++
++              if (lua_isnumber(L, 2)) {
++                      /* we have an extra parameter, ... lets see if it is a valid protocol
++                       * the parameter is the index of the 'supported_protocols'-array member */
++                      prot_type = lua_tointeger(L, 2);
++                      if (prot_type >= 0 && prot_type < PACKET_SENTINEL) {
++                              /* we are sure the purpose of the request is to get the payload data,
++                               * converted to the given protocol.  lets check if the payload contains
++                               * data of the given protocol */
++                              if (payload_contains_protocol(L, prot_buf, seg, prot_type)) {
++                                      /* success, we can  push the metatable for the given protocol */
++                                      get_metatable_from_protocol_type(L, prot_type);
++                                      if (!lua_isnil(L, -1))  /* check if the metatable was found */
++                                              /* perhaps the field offsets and lengths of the containing protocol
++                                               * are not set correctly. request the optional 'field_changes' structure
++                                               * holding the changes for lengths and offsets. */
++                                              new->changes = protocol_get_field_changes(L, get_protocol_buf(prot_type), new);
++                                      else{
++                                              /* failed, the requested protocol is not available
++                                               * we push false and return */
++                                              lua_pop(L, 1); /* pop the userdata */
++                                              lua_pushboolean(L, 0);
++                                              return 1;
++                                      }
++                              }else{
++                                      /* payload does not carry the provided protocol */
++                                      /* we push false and return */
++                                      lua_pop(L, 1); /* pop the userdata */
++                                      lua_pushboolean(L, 0);
++                                      return 1;
++                              }
++                      }else{
++                              /* unknown protocol */
++                              lua_pop(L, 1); /* pop the userdata */
++                              luaL_error(L, "provided protocol is unknown");
++                      }
++              }
++      }
++
++      /* if there is still the 'new' userdata on the top, we push our own metatable */
++      if (lua_isuserdata(L, -1)) {
++              luaL_getmetatable(L, prot_buf->name);
++              new->changes = seg->changes;
++              if (seg->changes)
++                      new->changes->ref_count++;
++      }
++
++      /* a new packet segment is at index -2 , and the proper metatable at index -1 of the stack
++       * lets set the propper setter and getter function for the requested field */
++      initialize_field_getter_and_setter(L, prot_buf, field_index);
++
++      lua_setmetatable(L, -2);
++      return 1;
++}
++
++/* C_API: 'register_protbuf' is only used internally. This function takes a
++ * pointer to a fully initialized protocol buffer struct and registers it
++ * inside the Lua state. Registering means:
++ *
++ * 1.  it creates a new metatable with the name of the protocol buffer.
++ * 2.  it registers the default functions which are stored in the luaL_Reg
++ *     array seg_access_functions.
++ * 3.  it loops over the protocol fields stored at prot_buf->protocol_fields
++ *     and registers a new function (using the field name) inside the
++ *     metatable. Each field points to the function 'get_protocol_field'
++ *     which acts as a closure taking a pointer to the protocol buffer as
++ *     well as the index of the field as upvalues.
++ * 4.  The protocol index, serves as numerical identifier of this protocol
++ *     buffer or even of the protocol itself. This index is stored as a
++ *     global value inside the Lua state as well as inside the Lua table
++ *     'supported_protocols'. Assuming the name of a procotol buffer is
++ *     "packet_ip" the following statements are true:
++ * 
++ *       supported_protocols[protocol_index] == "packet_ip"
++ *                                 packet_ip == protocol_index
++ *
++ *     This allows you to get all registered protocols from within Lua. This
++ *     is especially usefull for the dynamic protocol buffers where you have
++ *     to provide your own "has_protocol"-function, which probably needs the
++ *     information on which protocols it is able to contain.
++ */
++void register_protbuf(lua_State *L, struct protocol_buf * prot_buf, uint32_t  protocol_index)
++{
++      int32_t field_index;
++      luaL_Reg *reg = (struct luaL_Reg *)seg_access_functions;
++      struct protocol_field * field = prot_buf->protocol_fields;
++
++      luaL_newmetatable(L, prot_buf->name);
++
++      /* metatable.__index = metatable */
++      lua_pushvalue(L, -1);   /* duplicates the metatable */
++      lua_setfield(L, -2, "__index");
++
++      /* pushing default functions */
++      for (; reg->name; reg++) {
++              lua_pushlightuserdata(L, (void *)prot_buf);
++              lua_pushcclosure(L, reg->func, 1);
++              lua_setfield(L, -2, reg->name);
++      }
++
++      /* pushing functions specific to the protocol buffer */
++      for (field_index = 0; field->name; field++, field_index++) {
++              lua_pushlightuserdata(L, (void *)prot_buf);             /* upvalue: prot_buf */
++              lua_pushinteger(L, field_index);                        /* upvalue: index of protocol field */
++              lua_pushcclosure(L, get_protocol_field, 2);
++              lua_setfield(L, -2, field->name);
++      }
++      /* pop the metatable */
++      lua_pop(L, 1);
++
++      /* registering the array-index as the protocol_id*/
++      lua_getglobal(L, "_G");
++      lua_pushinteger(L, protocol_index);
++      lua_setfield(L, -2, prot_buf->name);
++      lua_pop(L, 1); /* pop _G */
++
++      lua_getglobal(L, SUPPORTED_PROTOCOL_TABLE);
++      lua_pushstring(L, prot_buf->name);
++      lua_rawseti(L, -2, protocol_index);
++
++      lua_pop(L, 1);  /* pop SUPPORTED_PROTOCOL_TABLE */
++
++      supported_protocols[protocol_index] = prot_buf;
++}
++
++void luaopen_controller(lua_State *L)
++{
++      /* registering a table inside the _G with table[protocol_index] = prot_buf->name */
++      lua_getglobal(L, "_G");
++      lua_newtable(L);
++      lua_setfield(L, -2, SUPPORTED_PROTOCOL_TABLE);
++      lua_pop(L, 1); /* pop _G */                   
++      
++      luaopen_protbuf_raw(L);
++      luaopen_protbuf_eth(L);
++      luaopen_protbuf_ip(L);
++      luaopen_protbuf_icmp(L);
++      luaopen_protbuf_tcp(L);
++      luaopen_protbuf_tcp_options(L);
++      luaopen_protbuf_udp(L);
++      luaopen_protbuf_tftp(L);
++      luaopen_protbuf_dynamic(L);
++      /* should follow all other static buffers */
++#if defined(__KERNEL__)
++      luaopen_nflib(L);
++#endif
++
++      luaopen_bytearraylib(L);
++}
++
++
++
++
+--- /dev/null
++++ b/extensions/LUA/controller.h
+@@ -0,0 +1,264 @@
++/*
++ *    Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *    by Andre Graf <andre@dergraf.org>
++ *
++ *    This program is free software; you can redistribute it and/or modify
++ *    it under the terms of the GNU General Public License as published by
++ *    the Free Software Foundation; either version 2 of the License, or
++ *    (at your option) any later version.
++ *
++ *    This program is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *    GNU General Public License for more details.
++ *
++ *    You should have received a copy of the GNU General Public License
++ *    along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CONTROLLER_H_
++#define CONTROLLER_H_
++
++#include "stdlib.h"     /* wrapper */
++#include "string.h"     /* wrapper */
++#include "lua.h"
++#include "lualib.h"
++#include "lauxlib.h"
++
++#if defined(__KERNEL__)
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#endif
++
++
++/* to compile the stuff in userspace (for testing)*/
++#if !defined(__KERNEL__)
++#include <stdint.h>
++#define pr_debug printf;
++
++#define kmalloc(size, type) malloc(size)
++#define kfree(ptr) free(ptr)
++
++#endif
++
++
++/**********************************************************************/
++/* nf Lua configuration                                               */
++/**********************************************************************/
++#define MAX_NR_OF_PROTOCOLS 16
++#define SUPPORTED_PROTOCOL_TABLE "supported_protocols"
++
++#define MAX_NR_OF_FIELDS_IN_DYN_PROT_BUF 32
++
++
++/**********************************************************************/
++/* Static Protocol Buffer configuration                               */
++/**********************************************************************/
++
++/* the definitions of the stringified expression of the prot_bufs...
++ * make sure all static prot_bufs are listed and are unique */
++#define LUA_PACKET_SEG_RAW "packet_raw"
++#define LUA_PACKET_SEG_ETH "packet_eth"
++#define LUA_PACKET_SEG_ICMP "packet_icmp"
++#define LUA_PACKET_SEG_IP "packet_ip"
++#define LUA_PACKET_SEG_TCP "packet_tcp"
++#define LUA_PACKET_SEG_TCP_OPT "packet_tcp_opt"
++#define LUA_PACKET_SEG_UDP "packet_udp"
++#define LUA_PACKET_SEG_TFTP "packet_tftp"
++
++/* the enum holding all static prot_bufs... make sure it contains all
++ * static prot_bufs */
++enum PROT_BUF {
++      PACKET_RAW,
++      PACKET_ETH,
++      PACKET_IP,
++      PACKET_ICMP,
++      PACKET_TCP,
++      PACKET_TCP_OPTIONS,
++      PACKET_UDP,
++      PACKET_TFTP,
++      PACKET_DYNAMIC,
++      PACKET_SENTINEL
++};
++
++/* the luaopen-function of the prot_bufs... make sure it is called
++ * inside luaopen_controller */
++void luaopen_protbuf_raw(lua_State *L);
++void luaopen_protbuf_eth(lua_State *L);
++void luaopen_protbuf_ip(lua_State *L);
++void luaopen_protbuf_icmp(lua_State *L);
++void luaopen_protbuf_tcp(lua_State *L);
++void luaopen_protbuf_tcp_options(lua_State *L);
++void luaopen_protbuf_udp(lua_State *L);
++void luaopen_protbuf_tftp(lua_State *L);
++void luaopen_protbuf_dynamic(lua_State *L);
++
++/**********************************************************************/
++/* field changes                                                      */
++/**********************************************************************/
++struct field_changes {
++      int ref_count;
++      int *field_length_changes;
++      int *field_offset_changes;
++};
++
++/**********************************************************************/
++/* lua packet segment                                                                                           */
++/* ------------------                                                 */
++/* The struct lua_packet_segment is the integral part of a Lua packet.*/
++/* At the very beginning, when a new packet arrives in `lua_tg`_ such */
++/* a struct is initialized. The field start then points to the lowest */
++/* available header inside the sk_buff structure. During packet       */
++/* processing the start pointer remains the same, only the offset and */
++/* length value change.                                               */
++/**********************************************************************/
++#define checkpacketseg(L, i, seg_type) \
++      (lua_packet_segment *)luaL_checkudata(L, i, seg_type)
++
++typedef struct lua_packet_segment {
++      unsigned int offset;
++      unsigned int length;
++      struct field_changes * changes;
++      unsigned char * start;  /* need to be at the end because of the memory alignment */
++} lua_packet_segment;
++
++/**********************************************************************/
++/* protocol field                                                     */
++/* --------------                                                                                                       */
++/* This structure is a container for the field definitions used by the*/
++/* protocol buffer. Each protocol field is expressed using this struct*/
++/* Have a look at the protocol buffers to see how the struct gets     */
++/* initialized.                                                                                                                 */
++/*                                                                                                                                      */
++/* name:                                                                                                                    */
++/*   This member expresses the name of the field, ending                        */
++/*   in its own Lua function to access the field.                                       */
++/* offset / length:                                                                                                     */
++/*   These members do specify the position inside the protocol header */
++/*   in bits (not bytes!).                                                                                      */
++/* get / set:                                                                                                           */
++/*   The get and set functions take a function pointer pointing to the*/
++/*   specific getter and setter function for this field.                        */
++/**********************************************************************/
++struct protocol_field {
++      const char * name;
++      uint32_t offset;
++      uint32_t length;
++      lua_CFunction get;
++      lua_CFunction set;
++};
++#define PROT_FIELD_SENTINEL { NULL, 0, 0, NULL, NULL }
++
++
++/**********************************************************************/
++/* protocol_buf                                                       */
++/**********************************************************************/
++/* This structure is a container for all the information needed for a
++ * protocol buffer. It gets initialized in each protocol buffer header
++ * file or for the dynamic protocol buffers on runtime using the
++ * 'register_dynamic_protocol_buffer' function.
++ *
++ * name:
++ *   This member is used throughout the system. It is also exported
++ *   to Lua as a variable name holding the index of the 'supported_protocols'
++ *   array. The name is also used as the name of the generated Lua
++ *   metatable, that is why inside the macro checkpacketseg_ it
++ *   is always the name of a protocol buffer that is passed as the
++ *   second parameter.
++ * payload_field:
++ *   This member holds the string of the field responsible for payload
++ *   data. The payload field of a protocol has an extra property, since
++ *   it can be used to invoke another protocol buffer that is applied to
++ *   the payload content.
++ * has_protocol:
++ *   This member is used together with the payload_field. Since we must
++ *   be sure that the payload content does really contain a protocol
++ *   of type X. The function pointed to by has_protocol checks if the
++ *   protocol buffer X can be applied on the payload_data.
++ * protocol_fields:
++ *   This member points to the array of 'protocol_field' structures
++ * get_field_changes:
++ *   This member is optional. It is used to return a pointer to an initialized
++ *   field_changes struct. The function is called, whenever the payload field
++ *   is requested with a given protocol type. Usually this function will
++ *   initialize the field_changes struct depending on the content of the 
++ *   payload data. e.g.
++ *     tcp = ip:data(packet_tcp)
++ *   such a request will call the 'get_field_changes' function of the tcp
++ *   protocol buffer. This enables, that the tcp options field have the proper
++ *   length as well as the tcp data start at the right offset. 
++ */
++struct protocol_buf {
++      int is_dynamic;
++      const char * name;
++      char * payload_field;
++      int (*has_protocol)(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg, int type);
++      struct protocol_field * protocol_fields;
++      struct field_changes * (*get_field_changes)(lua_State *L, lua_packet_segment * seg);
++};
++
++/**********************************************************************/
++/* lua byte array library                                             */
++/**********************************************************************/
++#define LUA_BYTE_ARRAY "byte_array"
++#define checkbytearray(L, i) \
++      (lua_packet_segment *)luaL_checkudata(L, i, LUA_BYTE_ARRAY)
++lua_packet_segment * init_byte_array(lua_State *L, unsigned char * start, int length, int do_copy);
++void luaopen_bytearraylib(lua_State *L);
++
++
++/**********************************************************************/
++/* lua netfilter environment library                                  */
++/**********************************************************************/
++#define NETFILTER_LIB "nf"
++#if defined(__KERNEL__)
++      struct lua_env {
++              lua_State *L;
++              /* perhaps more to come here (e.g. a state per CPU) */
++      }; 
++      #define LUA_ENV "lua_env"
++      #define checkluaenv(L, i) \
++      (struct lua_env *)luaL_checkudata(L, i, LUA_ENV)
++
++      void luaopen_nflib(lua_State *L);
++#endif
++
++void cleanup_dynamic_prot_bufs(void); /* freeing all dynamic prot bufs */
++/**********************************************************************/
++/* lua protbuf helpers                                                */
++/**********************************************************************/
++int get_1_bit_generic(lua_State *L);
++int set_1_bit_generic(lua_State *L);
++int get_lower_4_bit_generic(lua_State *L);
++int set_lower_4_bit_generic(lua_State *L);
++int get_upper_4_bit_generic(lua_State *L);
++int set_upper_4_bit_generic(lua_State *L);
++int get_8_bit_generic(lua_State *L);
++int set_8_bit_generic(lua_State *L);
++int get_16_bit_generic(lua_State *L);
++int set_16_bit_generic(lua_State *L);
++int get_32_bit_generic(lua_State *L);
++int set_32_bit_generic(lua_State *L);
++int set_data_generic(lua_State *L);
++int get_string_generic(lua_State *L);
++int get_byte_generic_str(lua_State *L);
++struct field_changes * get_allocated_field_changes(lua_State *L, int nr_of_fields);
++
++/* only used by the dynamic prot buf subsystem */
++#define MAX_NR_OF_DYN_PROT_BUFS 16
++int field_dynamic_setter(lua_State *L);
++int field_dynamic_getter(lua_State *L);
++int has_protocol_dynamic(lua_State *L, struct protocol_buf * prot_buf, lua_packet_segment * seg, int type);
++struct field_changes * get_field_changes_dynamic(lua_State *L, struct protocol_buf *prot_buf, lua_packet_segment * seg);
++
++/**********************************************************************/
++/* lua controller API                                                 */
++/**********************************************************************/
++void luaopen_controller(lua_State *L);
++struct protocol_buf * get_protocol_buf(unsigned int protocol_id);
++void get_metatable_from_protocol_type(lua_State *L, int type);
++void register_protbuf(lua_State *L, struct protocol_buf * prot_buf, unsigned int protocol_index);
++
++
++#endif /* CONTROLLER_H_ */
+--- /dev/null
++++ b/extensions/LUA/Kbuild
+@@ -0,0 +1,49 @@
++# -*- Makefile -*-
++
++# Adding debug options
++EXTRA_CFLAGS += -DDEBUG
++
++obj-m += xt_LUA.o
++
++EXTRA_CFLAGS += -I$(src)/prot_buf_new
++xt_LUA-y += xt_LUA_target.o \
++
++xt_LUA-y += nf_lua.o \
++                      prot_buf_helpers.o \
++                      byte_array.o \
++                      controller.o \
++                      prot_buf_ethernet.o \
++                      prot_buf_icmp.o \
++                      prot_buf_ip.o \
++                      prot_buf_raw.o \
++                      prot_buf_tcp.o \
++                      prot_buf_udp.o \
++                      prot_buf_tftp.o \
++                      prot_buf_dynamic.o \
++
++
++# Adding Lua Support
++EXTRA_CFLAGS += -I$(src)/lua -I$(src)/lua/include 
++xt_LUA-y += lua/lapi.o \
++                      lua/lbaselib.o \
++                      lua/lcode.o \
++                      lua/ldebug.o \
++                      lua/ldo.o \
++                      lua/ldump.o \
++                      lua/lfunc.o \
++                      lua/lgc.o \
++                      lua/llex.o \
++                      lua/lmem.o \
++                      lua/lobject.o \
++                      lua/lopcodes.o \
++                      lua/lparser.o \
++                      lua/lstate.o \
++                      lua/lstring.o \
++                      lua/lstrlib.o \
++                      lua/ltable.o \
++                      lua/ltablib.o \
++                      lua/ltm.o \
++                      lua/lundump.o \
++                      lua/lvm.o \
++                      lua/lzio.o \
++                      lua/lauxlib.o \
+--- /dev/null
++++ b/extensions/LUA/libxt_LUA.c
+@@ -0,0 +1,191 @@
++/*
++ *    Copyright (C) 2010 University of Basel <http://cn.cs.unibas.ch/>
++ *    by Andre Graf <andre@dergraf.org>
++ *
++ *    This program is free software; you can redistribute it and/or modify
++ *    it under the terms of the GNU General Public License as published by
++ *    the Free Software Foundation; either version 2 of the License, or
++ *    (at your option) any later version.
++ *
++ *    This program is distributed in the hope that it will be useful,
++ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *    GNU General Public License for more details.
++ *
++ *    You should have received a copy of the GNU General Public License
++ *    along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <getopt.h>
++#include <stdio.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include <xtables.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter/x_tables.h>
++#include "xt_LUA.h"
++
++enum {
++      FLAG_SCRIPT   = 1 << 0,
++      FLAG_STATE    = 1 << 1,
++      FLAG_FUNCTION = 1 << 2,
++};
++
++static const struct option lua_tg_opts[] = {
++      { .name = "script",   .has_arg = true, .val = 's' },
++      { .name = "state",    .has_arg = true, .val = 'l' },
++      { .name = "function", .has_arg = true, .val = 'f' },
++      { NULL },
++};
++
++
++static void lua_tg_help(void)
++{
++      printf(
++              "LUA target options:\n"
++              "  --script SCRIPT      Process packet with the Lua script given by SCRIPT\n"
++              "                                                                       \n"
++              "  --state ID           Process packet within the Lua state given by ID.\n"
++              "                       Omitting --state infers the ID 0, which can be\n"
++              "                       refered to the 'global' state.\n"
++              "                                                                       \n"
++              "  --function FUNCTION  Name of the function that processes the Lua packet\n"
++              "\n");
++}
++
++static void
++lua_tg_init(struct xt_entry_target *target)
++{
++      struct xt_lua_tginfo *info = (void *)target->data;
++
++      info->state_id = 0;
++      strncpy(info->function, "process_packet\0", sizeof("process_packet\0"));
++}
++
++static int
++lua_tg_parse(int32_t c, char **argv, int32_t invert, uint32_t  *flags,
++           const void *entry, struct xt_entry_target **target)
++{
++      struct xt_lua_tginfo *info = (void *)(*target)->data;
++      char buf[MAX_SCRIPT_SIZE];
++      long script_size;
++      uint32_t  state_id;
++      FILE *file;
++
++      switch (c) {
++      case 's':
++              if (*flags & FLAG_SCRIPT)
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Cannot specify --script more than once");
++
++              if (strlen(optarg) > sizeof(info->filename))
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Maximum script length is %zu",
++                                    sizeof(info->filename));
++
++              if (strchr(optarg, '\n'))
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Newlines not allowed in script name");
++              file = fopen(optarg, "rb");
++              if (file != NULL) {
++                      fseek(file, 0, SEEK_END);
++                      script_size = ftell(file);
++                      if (script_size > MAX_SCRIPT_SIZE)
++                              xtables_error(PARAMETER_PROBLEM,
++                                            "LUA: The size of the script is too big");
++
++                      fseek(file, 0, SEEK_SET);
++                      fread(buf, script_size, 1, file);
++                      fclose(file);
++              } else
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Cannot open script %s", optarg);
++
++              strncpy(info->filename, optarg, sizeof(info->filename));
++              strncpy(info->buf, buf, sizeof(info->buf));
++              info->script_size = script_size;
++
++              *flags |= FLAG_SCRIPT;
++              return true;
++
++      case 'l':
++              if (*flags & FLAG_STATE)
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Cannot specify --state more than once");
++
++              if (!xtables_strtoui(optarg, NULL, &state_id, 0, 8))
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Invalid --state %s", optarg);
++
++              info->state_id = state_id;
++              *flags |= FLAG_STATE;
++              return true;
++
++      case 'f':
++              if (*flags & FLAG_FUNCTION)
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Cannot specify --function more than once");
++              if (strlen(optarg) > sizeof(info->function))
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Maximum function length is %zu",
++                                    sizeof(info->function));
++
++              if (strchr(optarg, '\n'))
++                      xtables_error(PARAMETER_PROBLEM,
++                                    "LUA: Newlines not allowed in function name");
++
++              strncpy(info->function, optarg, sizeof(info->function));
++
++              *flags |= FLAG_FUNCTION;
++              return true;
++      }
++
++      return false;
++}
++
++static void
++lua_tg_check(uint32_t  flags)
++{
++      if (flags == 0)
++              xtables_error(PARAMETER_PROBLEM, "LUA: --script parameter required");
++}
++
++static void
++lua_tg_print(const void *entry, const struct xt_entry_target *target,
++           int32_t numeric)
++{
++      const struct xt_lua_tginfo *info = (const void *)target->data;
++
++      printf("LUA script: %s ", info->filename);
++}
++
++static void
++lua_tg_save(const void *entry, const struct xt_entry_target *target)
++{
++      const struct xt_lua_tginfo *info = (const void *)target->data;
++
++      printf("--script %s ", info->filename);
++}
++
++static struct xtables_target lua_tg_reg = {
++      .name                   = "LUA",
++      .version                = XTABLES_VERSION,
++      .revision               = 0,
++      .family                 = NFPROTO_UNSPEC,
++      .size                   = XT_ALIGN(sizeof(struct xt_lua_tginfo)),
++      .userspacesize          = XT_ALIGN(sizeof(struct xt_lua_tginfo)),
++      .help                   = lua_tg_help,
++      .init                   = lua_tg_init,
++      .parse                  = lua_tg_parse,
++      .final_check            = lua_tg_check,
++      .print                  = lua_tg_print,
++      .save                   = lua_tg_save,
++      .extra_opts             = lua_tg_opts,
++};
++
++static __attribute__((constructor)) void lua_tg_ldr(void)
++{
++      xtables_register_target(&lua_tg_reg);
++}
++
+--- /dev/null
++++ b/extensions/LUA/libxt_LUA.man
+@@ -0,0 +1 @@
++Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+--- /dev/null
++++ b/extensions/LUA/lua/include/ctype.h
+@@ -0,0 +1,11 @@
++#include <linux/ctype.h>
++#undef  isalnum
++#define isalnum(c)      (((__ismask(c)&(_U|_L|_D)) != 0) && (c > 0))
++#undef  isalpha
++#define isalpha(c)      (((__ismask(c)&(_U|_L)) != 0) && (c > 0))
++#undef  iscntrl
++#define iscntrl(c)      (((__ismask(c)&(_C)) != 0) && (c > 0))
++#undef  isdigit
++#define isdigit(c)      (((__ismask(c)&(_D)) != 0) && (c > 0))
++#undef  isspace
++#define isspace(c)      (((__ismask(c)&(_S)) != 0) && (c > 0))
+--- /dev/null
++++ b/extensions/LUA/lua/include/errno.h
+@@ -0,0 +1 @@
++#include <linux/errno.h>
+--- /dev/null
++++ b/extensions/LUA/lua/include/locale.h
+@@ -0,0 +1,5 @@
++struct lconv {
++   char * decimal_point ;
++} ;
++
++#define localeconv()          NULL
+--- /dev/null
++++ b/extensions/LUA/lua/include/setjmp.h
+@@ -0,0 +1,26 @@
++/*
++ * arch/um/include/sysdep-i386/archsetjmp.h
++ */
++
++#ifndef _KLIBC_ARCHSETJMP_H
++#define _KLIBC_ARCHSETJMP_H
++
++struct __jmp_buf {
++      unsigned int __ebx;
++      unsigned int __esp;
++      unsigned int __ebp;
++      unsigned int __esi;
++      unsigned int __edi;
++      unsigned int __eip;
++};
++
++typedef struct __jmp_buf jmp_buf[1];
++
++#define JB_IP __eip
++#define JB_SP __esp
++
++int setjmp(jmp_buf);
++void longjmp(jmp_buf, int);
++
++#endif                                /* _SETJMP_H */
++
+--- /dev/null
++++ b/extensions/LUA/lua/include/stdio.h
+@@ -0,0 +1 @@
++#include <linux/kernel.h>
+--- /dev/null
++++ b/extensions/LUA/lua/include/stdlib.h
+@@ -0,0 +1,7 @@
++#include <linux/kernel.h>
++
++#define exit(E)         return
++#define strtoul               simple_strtoul
++#define strcoll               strcmp
++
++#define CHAR_BIT 8
+--- /dev/null
++++ b/extensions/LUA/lua/include/string.h
+@@ -0,0 +1 @@
++#include <linux/string.h>
+--- /dev/null
++++ b/extensions/LUA/lua/lapi.c
+@@ -0,0 +1,1086 @@
++/*
++** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $
++** Lua API
++** See Copyright Notice in lua.h
++*/
++
++#include <stdarg.h>
++#include <math.h>
++#include <assert.h>
++#include <string.h>
++
++#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"
++
++
++
++const char lua_ident[] =
++  "$Lua: " LUA_RELEASE " " LUA_COPYRIGHT " $\n"
++  "$Authors: " LUA_AUTHORS " $\n"
++  "$URL: www.lua.org $\n";
++
++
++
++#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 = 1;
++  lua_lock(L);
++  if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
++    res = 0;  /* stack overflow */
++  else if (size > 0) {
++    luaD_checkstack(L, size);
++    if (L->ci->top < L->top + size)
++      L->ci->top = L->top + size;
++  }
++  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;
++        }
++      }
++      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;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lapi.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/lauxlib.c
+@@ -0,0 +1,674 @@
++/*
++** $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
++*/
++
++#include <stdarg.h>
++
++#if !defined(__KERNEL__)
++#include <ctype.h>
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#else
++#include <linux/ctype.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#endif
++
++/* 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_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
++  if(!b) luaL_error(L, "luaL_gsub: cannot allocate memory");
++  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);
++  kfree(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
++** =======================================================
++*/
++
++#if !defined(__KERNEL__)
++typedef struct LoadF {
++  int extraline;
++  FILE *f;
++  char buff[LUAL_BUFFERSIZE];
++} LoadF;
++
++
++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";
++  }
++  if (feof(lf->f)) return NULL;
++  *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
++  return (*size > 0) ? lf->buff : NULL;
++}
++
++
++static int errfile (lua_State *L, const char *what, int fnameindex) {
++  const char *serr = strerror(errno);
++  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");
++    lf.f = stdin;
++  }
++  else {
++    lua_pushfstring(L, "@%s", filename);
++    lf.f = fopen(filename, "r");
++    if (lf.f == NULL) return errfile(L, "open", fnameindex);
++  }
++  c = getc(lf.f);
++  if (c == '#') {  /* Unix exec. file? */
++    lf.extraline = 1;
++    while ((c = getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */
++    if (c == '\n') c = getc(lf.f);
++  }
++  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */
++    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */
++    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
++    /* skip eventual `#!...' */
++   while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
++    lf.extraline = 0;
++  }
++  ungetc(c, lf.f);
++  status = lua_load(L, getF, &lf, lua_tostring(L, -1));
++  readstatus = ferror(lf.f);
++  if (filename) fclose(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;
++}
++#endif
++
++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) {
++#if !defined(__KERNEL__)
++    free(ptr);
++#else
++    kfree(ptr);
++#endif
++    return NULL;
++  }
++  else
++#if !defined(__KERNEL__)
++    return realloc(ptr, nsize);
++#else
++    return krealloc(ptr, nsize, GFP_ATOMIC);
++#endif
++}
++
++
++static int lpanic (lua_State *L) {
++  (void)L;  /* to avoid warnings */
++#if !defined(__KERNEL__)
++  fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n",
++#else
++  printk( "PANIC: unprotected error in call to Lua API (%s)\n",
++#endif
++                   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, &lpanic);
++  return L;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lauxlib.h
+@@ -0,0 +1,184 @@
++/*
++** $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>
++#include <linux/slab.h>       /* for kmalloc and kfree when allocating luaL_Buffer */
++
++#if !defined(__KERNEL__)
++#include <stdio.h>
++#endif
++
++#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);
++
++#if !defined(__KERNEL__)
++LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
++#endif
++
++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)))
++
++#if !defined(__KERNEL__)
++#define luaL_dofile(L, fn) \
++      (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
++#endif
++
++#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
++
++
+--- /dev/null
++++ b/extensions/LUA/lua/lbaselib.c
+@@ -0,0 +1,647 @@
++/*
++** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $
++** Basic library
++** See Copyright Notice in lua.h
++*/
++
++
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++
++#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"));
++    printk(KERN_INFO "LUA[print]: %s", s);
++    lua_pop(L, 1);  /* pop result */
++  }
++  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 = simple_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));
++  if (i > e) return 0;  /* empty range */
++  n = e - i + 1;  /* number of elements */
++  if (n <= 0 || !lua_checkstack(L, n))  /* n <= 0 means arith. overflow */
++    return luaL_error(L, "too many results to unpack");
++  lua_rawgeti(L, 1, i);  /* push arg[i] (avoiding overflow problems) */
++  while (i++ < e)  /* push arg[i + 1...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 + 1))
++      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;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lcode.c
+@@ -0,0 +1,838 @@
++/*
++** $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
++*/
++
++#include <stdlib.h>
++
++#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 */
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lcode.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/ldebug.c
+@@ -0,0 +1,637 @@
++/*
++** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $
++** Debug Interface
++** See Copyright Notice in lua.h
++*/
++
++
++#include <stdarg.h>
++#include <stddef.h>
++#include <string.h>
++
++#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);
++  check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
++  check(!(pt->is_vararg & VARARG_NEEDSARG) ||
++              (pt->is_vararg & VARARG_HASARG));
++  check(pt->sizeupvalues <= pt->nups);
++  check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
++  check(pt->sizecode > 0 && 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) {
++            int j;
++            /* check that it does not jump to a setlist count; this
++               is tricky, because the count from a previous setlist may
++               have the same value of an invalid setlist; so, we must
++               go all the way back to the first of them (if any) */
++            for (j = 0; j < dest; j++) {
++              Instruction d = pt->code[dest-1-j];
++              if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break;
++            }
++            /* if 'j' is even, previous value is not a setlist (even if
++               it looks like one) */
++            check((j&1) == 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: {
++        if (c == 1) {  /* does it jump? */
++          check(pc+2 < pt->sizecode);  /* check its jump */
++          check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST ||
++                GETARG_C(pt->code[pc+1]) != 0);
++        }
++        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++;
++          check(pc < pt->sizecode - 1);
++        }
++        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);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldebug.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/ldo.c
+@@ -0,0 +1,515 @@
++/*
++** $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
++*/
++
++#include <setjmp.h>
++#include <stdlib.h>
++#include <string.h>
++
++#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;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldo.h
+@@ -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
++
+--- /dev/null
++++ b/extensions/LUA/lua/ldump.c
+@@ -0,0 +1,164 @@
++/*
++** $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
++*/
++
++#include <stddef.h>
++
++#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;
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lfunc.c
+@@ -0,0 +1,174 @@
++/*
++** $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
++*/
++
++
++#include <stddef.h>
++
++#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 */
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lfunc.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/lgc.c
+@@ -0,0 +1,711 @@
++/*
++** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
++** Garbage Collector
++** See Copyright Notice in lua.h
++*/
++
++#include <string.h>
++
++#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);
++    }
++  }
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lgc.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/llex.c
+@@ -0,0 +1,460 @@
++/*
++** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
++** Lexical Analyzer
++** See Copyright Notice in lua.h
++*/
++
++#include <ctype.h>
++#include <locale.h>
++#include <string.h>
++
++#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;
++  struct lconv *cv = localeconv();
++  ls->decpoint = (cv ? cv->decimal_point[0] : '.');
++  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);
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/llex.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/llimits.h
+@@ -0,0 +1,125 @@
++/*
++** $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
++
++#include <stddef.h>
++#include <limits.h>
++
++#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 (LUA_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
++
++
++#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
+--- /dev/null
++++ b/extensions/LUA/lua/lmem.c
+@@ -0,0 +1,86 @@
++/*
++** $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
++*/
++
++
++#include <stddef.h>
++
++#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;
++}
++
+--- /dev/null
++++ b/extensions/LUA/lua/lmem.h
+@@ -0,0 +1,49 @@
++/*
++** $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
++
++
++#include <stddef.h>
++
++#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
++
+--- /dev/null
++++ b/extensions/LUA/lua/lobject.c
+@@ -0,0 +1,215 @@
++/*
++** $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
++*/
++
++#include <stdarg.h>
++
++#include <ctype.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#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, "\"]");
++    }
++  }
++}
+--- /dev/null
++++ b/extensions/LUA/lua/lobject.h
+@@ -0,0 +1,381 @@
++/*
++** $Id: lobject.h,v 2.20.1.2 2008/08/06 13:29:48 roberto Exp $
++** Type definitions for Lua objects
++** See Copyright Notice in lua.h
++*/
++
++
++#ifndef lobject_h
++#define lobject_h
++
++
++#include <stdarg.h>
++
++
++#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(rawtsvalue(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
++
+--- /dev/null
++++ b/extensions/LUA/lua/lopcodes.c
+@@ -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 */
++};
++
+--- /dev/null
++++ b/extensions/LUA/lua/lopcodes.h
+@@ -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
+--- /dev/null
++++ b/extensions/LUA/lua/lparser.c
+@@ -0,0 +1,1339 @@
++/*
++** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
++** Lua Parser
++** See Copyright Notice in lua.h
++*/
++
++
++#include <string.h>
++
++#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;
++ &nb