diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2012, Tom Schouten
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Tom Schouten nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,47 @@
+Gather C structs tagged with __attribute__((__packed__)) and enum
+definitions into a Lua data structure.  This allows conversion between
+binary blobs and Lua tables using functions parse-bin.lua provides,
+useful for C applications with an embedded Lua interpreter.
+
+This tool is a thin wrapper around the awesome Language.C library:
+http://hackage.haskell.org/package/language-c
+
+
+BUILD
+
+( Instructions for Debian )        
+
+# Optionally add ~/.cabal/bin to your search path.  This is where
+# cabal will install Haskell binaries, including the updated version
+# of cabal itself.
+
+apt-get install cabal-install haskell-platform
+cabal update
+cabal install cabal-install
+cabal install pretty-show
+cabal install happy
+cabal install language-c
+
+tar xf packed_lua.tar.gz
+cd packed_lua
+
+# The 2 commands below also appear in the Makefile.
+
+cabal configure
+cabal build
+
+# At this point the binary will be in the local directory:
+# dist/build/packed-lua/packed-lua
+# Optionally install it to ~/.cabal/bin using:
+
+cabal install
+
+
+
+USAGE
+
+Provide the (possibly prepocessed) C file as a first argument and
+gather the Lua output on stdout, i.e:
+
+  packed_lua structs.c >sym.lua
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/clua.cabal b/clua.cabal
new file mode 100644
--- /dev/null
+++ b/clua.cabal
@@ -0,0 +1,22 @@
+Name:                clua
+Version:             0.1
+Synopsis:            C to Lua data wrapper generator
+Homepage:            http://zwizwa.be/-/meta
+License:             BSD3
+License-file:        LICENSE
+Author:              Tom Schouten
+Maintainer:          tom@zwizwa.be
+Category:            Language
+Build-type:          Simple
+Extra-source-files:  README, parse-bin.lua
+Cabal-version:       >=1.2
+
+Description: Gather enums and packed struct definitions from a C file
+             and generate a Lua table that can be used in conjunction
+             with parse-bin.lua to convert between Lua tables and
+             binary data.
+
+Executable clua
+  Main-is: clua.hs
+  Build-depends: base < 5, haskell98, pretty, containers,
+                 language-c, pretty-show, bytestring
diff --git a/clua.hs b/clua.hs
new file mode 100644
--- /dev/null
+++ b/clua.hs
@@ -0,0 +1,16 @@
+import CAnalyze  -- wrappers around Language.C analysis
+import PrintLua
+import System
+
+usage me =
+  putStrLn $ "usage: " ++ me ++ " <c-file>"
+
+
+main = do
+  args <- getArgs
+  me <- getProgName
+  case args of
+    -- [file] -> report (aKeys packedStructs) file
+    [file] -> packedLua file
+    _ -> usage me
+
diff --git a/parse-bin.lua b/parse-bin.lua
new file mode 100644
--- /dev/null
+++ b/parse-bin.lua
@@ -0,0 +1,147 @@
+-- Goes together with the struct wrapper generator.
+
+-- Tools
+local function table_copy(t)
+  local u = { }
+  for k, v in pairs(t) do u[k] = v end
+  return setmetatable(u, getmetatable(t))
+end
+
+
+parse = {}
+
+-- Wrap table as abstract stream.
+function parse.array2stream(arr)
+   if (arr) then
+      local i = 0
+      return
+      function()
+         i = i + 1
+         return arr[i]
+      end
+   else
+      -- Allow arr to be nil in case we assume it's a stream of zeros.
+      return
+      function() 
+         return 0
+      end
+   end
+end
+
+-- Parsers for "int", "float", "struct", "array"
+function parse.int(stream, structs, signed, bits)
+   local bytes = bits/8
+   local accu = 0
+   local shift = 1
+   local byte = 0
+   while (bytes > 0) do
+      byte = assert(stream())
+      accu = accu + shift * byte;
+      shift = shift * 0x100
+      bytes = bytes - 1
+   end
+   if ((signed == 'S') and (byte > 0x7F)) then
+      accu = accu - shift
+   end
+   return accu
+end
+
+function parse.float()
+   assert(nil) -- FIXME
+end
+
+function parse.struct(stream, structs, struct_name)
+   return parse.table(stream, structs, structs[struct_name])
+end
+
+function parse.array(stream, structs, size, type_spec)
+   if (size == 0) then
+      return {}
+   else
+      local arr = {}
+      for i=1, size do
+         arr[i] = parse.type(stream, structs, type_spec)
+      end
+      return arr
+   end
+end
+
+
+
+-- Element dispatcher.
+function parse.type(stream, structs, type_spec)
+   local spec = table_copy(type_spec)
+   local type = assert(table.remove(spec,1))
+   -- print (type)
+   local fun = assert(parse[type])
+   return fun(stream, structs, table.unpack(spec))
+end
+
+-- Table dispatcher
+function parse.table(stream, structs, tab_spec) 
+   local tab = {}
+   for i,rec_spec in pairs(tab_spec) do
+      local type_spec, name = table.unpack(rec_spec)
+      tab[name] = parse.type(stream, structs, type_spec)
+   end
+   return tab
+end
+
+-- Functional interface
+function parse.array2table (array, structs, tab_spec)
+   return parse.table (parse.array2stream(array), structs, tab_spec)
+end
+
+
+-- Wrap table as abstract stream.
+unparse = {}
+function unparse.array2stream(t)
+   return
+   function(byte)
+      table.insert(t, byte)
+   end
+end
+
+function unparse.int(stream, val, structs, signed, bits)
+   local bytes = bits/8
+   local accu = val
+   while (bytes > 0) do
+      local byte = accu % 0x100
+      stream(byte)
+      accu = math.floor(accu / 0x100)
+      bytes = bytes - 1
+   end
+end
+
+function unparse.struct(stream, val, structs, struct_name)
+   unparse.table(stream, val, structs, structs[struct_name])
+end
+
+function unparse.array(stream, arr, structs, size, type_spec)
+   if (size > 0) then
+      for i=1,size do
+         unparse.type(stream, arr[i], structs, type_spec)
+      end
+   end
+end
+
+function unparse.type(stream, val, structs, type_spec)
+   local spec = table_copy(type_spec)
+   local type = assert(table.remove(spec,1))
+   -- print (type)
+   unparse[type](stream, val, structs, table.unpack(spec))
+end
+
+function unparse.table(stream, tab, structs, tab_spec) 
+   for i,rec_spec in pairs(tab_spec) do
+      local type_spec, name = table.unpack(rec_spec)
+      unparse.type(stream, tab[name], structs, type_spec)
+   end
+end
+
+-- Functional interface
+function unparse.table2array(tab, structs, tab_spec)
+   local arr = {}
+   unparse.table(unparse.array2stream(arr), tab, structs, tab_spec)
+   return arr
+end
