shithub: lua9

Download patch

ref: e3a3564affde308600a8bd534df38a0e9229efba
parent: f00064c3e10452efe86d9a646c54b074d6da54b0
author: telephil9 <telephil9@gmail.com>
date: Sun Oct 25 05:09:10 EDT 2020

Major code refactoring

	Much needed code cleanup after what was a POC style initial version:
	- Stick to plan9 C coding standards
	- Split code in several files for readability
	- Expose constants as uppercase to match lua coding standards
	- Added a key module to expose known key constants

--- a/README.md
+++ b/README.md
@@ -1,21 +1,23 @@
 # About
 
 lua9 is a custom version of the [lua](http://lua.org) interpreter including bindings to plan9 libdraw.  
-This relies on the [lua 5.4 port](https://github.com/staalmannen/lua) for plan9 by [staalmannen](https://github.com/staalmannen).
 
-Disclaimer: This is work in progress and is sure to contain bugs.
+__Disclaimer:__ This is work in progress and is sure to contain bugs.
 
 # Installation
 
-First, install the lua 5.4 port for plan9.  
+Make sure to have [git9](http://github.com/oridb/git9] installed first.
 
-Clone the sources using the [git9](https://github.com/oridb/git9) client:
+Install the [lua 5.4 port](https://github.com/staalmannen/lua) for plan9 by [staalmannen](https://github.com/staalmannen).  
 ```sh
-% git/clone git://github.com/telephil9/lua9
+% git/clone git://github.com/staalmannen/lua
+% cd lua
+% mk install
 ```
 
-Install the lua9 interpreter:
+Install lua9:  
 ```sh
+% git/clone git://github.com/telephil9/lua9
 % cd lua9
 % mk install
 ```
@@ -25,8 +27,10 @@
 ```sh
 % ape/lua9 <script.lua>
 ```
-It is also possible to use a shebang script.
 
-# Credits
+You can also start your lua script with `#!/bin/ape/lua9`.
 
-- Philippe ([telephil9](https://github.com/telephil9/))
+# Documentation
+
+TODO
+
--- /dev/null
+++ b/display.c
@@ -1,0 +1,87 @@
+#include <draw.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "ldraw.h"
+#include "utils.h"
+
+#define DISPLAY "Display"
+
+typedef struct LDisplay LDisplay;
+
+struct LDisplay
+{
+	Display *d;
+};
+
+void
+pushdisplay(lua_State *L, Display *d)
+{
+	LDisplay *l;
+
+	l = (LDisplay*)lua_newuserdata(L, sizeof(LDisplay));
+	luaL_getmetatable(L, DISPLAY);
+	lua_setmetatable(L, -2);
+	l->d = d;
+}
+
+Display*
+checkdisplay(lua_State *L, int index)
+{
+	LDisplay *l;
+
+	l = (LDisplay*)luaL_checkudata(L, index, DISPLAY);
+	luaL_argcheck(L, l != NULL, index, "Display expected");
+	return l->d;
+}
+
+static int
+display__gc(lua_State *L)
+{
+	/* we do not GC the display */
+	lua_pushboolean(L, 0);
+	return 1;
+}
+
+static int
+display__tostring(lua_State *L) 
+{
+	void *p;
+
+	p = lua_touserdata(L, 1);
+	lua_pushfstring(L, "display: %p", p);
+	return 1;
+}
+
+static int
+display__index(lua_State *L)
+{
+	Display *d;
+	const char *s;
+
+	d = checkdisplay(L, 1);
+	s = luaL_checkstring(L, 2);
+	if(strncmp(s, "white", 5) == 0)
+		pushimage(L, d->white);
+	else if(strncmp(s, "black", 5) == 0)
+		pushimage(L, d->black);
+	else
+		return 0;
+	return 1;
+}
+
+static const struct luaL_Reg display_funcs[] = {
+	{ "__gc", display__gc },
+	{ "__tostring", display__tostring },
+	{ "__index", display__index },
+	{ NULL, NULL },
+};
+
+void
+registerdisplaymeta(lua_State *L)
+{
+	createmetatable(L, DISPLAY, display_funcs);
+}
+
--- /dev/null
+++ b/font.c
@@ -1,0 +1,94 @@
+#include <draw.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include "ldraw.h"
+#include "utils.h"
+
+#define FONT "Font"
+
+typedef struct LFont LFont;
+
+struct LFont
+{
+	Font *f;
+};
+
+void
+pushfont(lua_State *L, Font *f)
+{
+	LFont *l;
+
+	l = (LFont*)lua_newuserdata(L, sizeof(LFont));
+	luaL_getmetatable(L, FONT);
+	lua_setmetatable(L, -2);
+	l->f = f;
+}
+
+Font*
+checkfont(lua_State *L, int index)
+{
+	LFont *l;
+
+	l = (LFont*)luaL_checkudata(L, index, FONT);
+	luaL_argcheck(L, l != NULL, index, "Font expected");
+	return l->f;
+}
+
+static int
+font__gc(lua_State *L)
+{
+	/* TODO */
+	lua_pushboolean(L, 0);
+	return 1;
+}
+
+static int
+font__tostring(lua_State *L)
+{
+	void *p;
+
+	p = lua_touserdata(L, 1);
+	lua_pushfstring(L, "font: %p", p);
+	return 1;
+}
+
+static int
+font__index(lua_State *L)
+{
+	Font *f;
+	const char *s;
+
+	f = checkfont(L, 1);
+	s = luaL_checkstring(L, 2);
+	if(strncmp(s, "name", 4) == 0)
+		lua_pushstring(L, f->name);
+	else if(strncmp(s, "height", 6) == 0)
+		lua_pushinteger(L, f->height);
+	else if(strncmp(s, "ascent", 6) == 0)
+		lua_pushinteger(L, f->ascent);
+	else if(strncmp(s, "width", 5) == 0)
+		lua_pushinteger(L, f->width);
+	else if(strncmp(s, "nsub", 4) == 0)
+		lua_pushinteger(L, f->nsub);
+	else if(strncmp(s, "age", 3) == 0)
+		lua_pushinteger(L, f->age);
+	else
+		return 0;
+	return 1;
+}
+
+static const struct luaL_Reg font_funcs[] = {
+	{ "__gc", font__gc },
+	{ "__tostring", font__tostring },
+	{ "__index", font__index },
+	{ NULL, NULL },
+};
+
+void
+registerfontmeta(lua_State *L)
+{
+	createmetatable(L, FONT, font_funcs);
+}
--- /dev/null
+++ b/geometry.c
@@ -1,0 +1,91 @@
+#include <draw.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+void
+pushrect(lua_State *L, Rectangle r)
+{
+	lua_newtable(L);
+	lua_newtable(L);
+	lua_pushinteger(L, r.min.x);
+	lua_setfield(L, -2, "x");
+	lua_pushinteger(L, r.min.y);
+	lua_setfield(L, -2, "y");
+	lua_setfield(L, -2, "min");
+	lua_newtable(L);
+	lua_pushinteger(L, r.max.x);
+	lua_setfield(L, -2, "x");
+	lua_pushinteger(L, r.max.y);
+	lua_setfield(L, -2, "y");
+	lua_setfield(L, -2, "max");
+}
+
+Rectangle
+checkrect(lua_State *L, int index)
+{
+	Rectangle r;
+
+	if(lua_istable(L, index) == 0)
+		luaL_argerror(L, index, "rectangle table expected");
+	lua_pushstring(L, "min");
+	lua_gettable(L, index);
+	lua_pushstring(L, "x");
+	lua_gettable(L, -2);
+	r.min.x = luaL_checkinteger(L, -1);
+	lua_pushstring(L, "y");
+	lua_gettable(L, -3);
+	r.min.y = luaL_checkinteger(L, -1);
+	lua_pop(L, 3); /* table | x | y */
+	lua_pushstring(L, "max");
+	lua_gettable(L, index);
+	lua_pushstring(L, "x");
+	lua_gettable(L, -2);
+	r.max.x = luaL_checkinteger(L, -1);
+	lua_pushstring(L, "y");
+	lua_gettable(L, -3);
+	r.max.y = luaL_checkinteger(L, -1);
+	lua_pop(L, 3);
+	return r;
+}
+
+void
+pushpoint(lua_State *L, Point p)
+{
+	lua_newtable(L);
+	lua_pushinteger(L, p.x);
+	lua_setfield(L, -2, "x");
+	lua_pushinteger(L, p.y);
+	lua_setfield(L, -2, "y");
+}
+
+Point
+getpoint(lua_State *L, int index)
+{
+	Point p;
+
+	lua_pushstring(L, "x");
+	lua_gettable(L, index);
+	p.x = luaL_checkinteger(L, -1);
+	lua_pushstring(L, "y");
+	lua_gettable(L, index);
+	p.y = luaL_checkinteger(L, -1);
+	lua_pop(L, 2);
+	return p;
+}
+
+Point
+checkpoint(lua_State *L, int index)
+{
+	if(lua_istable(L, index) == 0)
+		luaL_argerror(L, index, "point table expected");
+	return getpoint(L, index);
+}
+
+Point
+optpoint(lua_State *L, int index)
+{
+	if(lua_istable(L, index) == 0)
+		return ZP;
+	return getpoint(L, index);
+}
--- /dev/null
+++ b/image.c
@@ -1,0 +1,107 @@
+#include <draw.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "ldraw.h"
+#include "utils.h"
+
+#define IMAGE "Image"
+
+typedef struct LImage LImage;
+
+struct LImage
+{
+	Image *i;
+};
+
+void pushimage(lua_State *L, Image *i)
+{
+	LImage *l;
+
+	l = (LImage*)lua_newuserdata(L, sizeof(LImage));
+	luaL_getmetatable(L, IMAGE);
+	lua_setmetatable(L, -2);
+	l->i = i;
+}
+
+Image*
+checkimage(lua_State *L, int index)
+{
+	LImage *l;
+
+	l = (LImage*)luaL_checkudata(L, index, IMAGE);
+	luaL_argcheck(L, l != NULL, index, "Image expected");
+	return l->i;
+}
+
+Image*
+optimage(lua_State *L, int index)
+{
+	if(lua_isnil(L, index))
+		return nil;
+	return checkimage(L, index);
+}
+
+static int
+image__gc(lua_State *L)
+{
+	Image *i;
+
+	i = checkimage(L, 1);
+	if(i == screen) {
+		lua_pushboolean(L, 0);
+		return 1;
+	}
+	/* TODO freeimage */
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+static int
+image__tostring(lua_State *L)
+{
+	void *p;
+	char buf[64];
+
+	p = lua_touserdata(L, 1);
+	lua_pushfstring(L, "image: %p", p);
+	return 1;
+}
+
+static int
+image__index(lua_State *L)
+{
+	Image *i;
+	const char *s;
+
+	i = checkimage(L, 1);
+	s = luaL_checkstring(L, 2);
+	if(!strncmp(s, "r", 1))
+		pushrect(L, i->r);
+	else if(!strncmp(s, "clipr", 5))
+		pushrect(L, i->clipr);
+	else if(!strncmp(s, "chan", 4))
+		lua_pushinteger(L, i->chan);
+	else if(!strncmp(s, "depth", 5))
+		lua_pushinteger(L, i->depth);
+	else if(!strncmp(s, "repl", 4))
+		lua_pushinteger(L, i->repl);
+	else
+		return 0;
+	return 1;
+}
+
+static const struct luaL_Reg image_funcs[] = {
+	{ "__gc", image__gc },
+	{ "__tostring", image__tostring },
+	{ "__index", image__index },
+	{ NULL, NULL },
+};
+
+void
+registerimagemeta(lua_State *L)
+{
+	createmetatable(L, IMAGE, image_funcs);
+}
--- /dev/null
+++ b/key.c
@@ -1,0 +1,50 @@
+#include <keyboard.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include "utils.h"
+
+static int
+lkeyeq(lua_State *L)
+{
+	int i;
+	const char *s;
+
+	i = luaL_checkinteger(L, 1);
+	s = luaL_checkstring(L, 2);
+	lua_pushboolean(L, i==*s);
+	return 1;
+}
+
+static const struct luaL_Reg libkey[] = {
+	{ "eq", lkeyeq },
+	{ NULL, NULL },
+};
+
+int
+openlibkey(lua_State *L)
+{
+	luaL_newlib(L, libkey);
+	pushglobal(L, "HOME", Khome);
+	pushglobal(L, "UP", Kup);
+	pushglobal(L, "DOWN", Kdown);
+	pushglobal(L, "PGUP", Kpgup);
+	pushglobal(L, "PRINT", Kprint);
+	pushglobal(L, "LEFT", Kleft);
+	pushglobal(L, "RIGHT", Kright);
+	pushglobal(L, "PGDOWN", Kpgdown);
+	pushglobal(L, "INS", Kins);
+	pushglobal(L, "END", Kend);
+	pushglobal(L, "SOH", Ksoh);
+	pushglobal(L, "STX", Kstx);
+	pushglobal(L, "ETX", Ketx);
+	pushglobal(L, "EOF", Keof);
+	pushglobal(L, "ENQ", Kenq);
+	pushglobal(L, "ACK", Kack);
+	pushglobal(L, "BS", Kbs);
+	pushglobal(L, "NACK", Knack);
+	pushglobal(L, "ETB", Ketb);
+	pushglobal(L, "DEL", Kdel);
+	pushglobal(L, "ESC", Kesc);
+	return 1;
+}
--- /dev/null
+++ b/ldraw.h
@@ -1,0 +1,32 @@
+#ifndef LDRAW_H__
+#define LDRAW_H__
+
+/* display */
+void registerdisplaymeta(lua_State *L);
+void pushdisplay(lua_State *L, Display *d);
+Display* checkdisplay(lua_State *L, int index);
+
+/* font */
+void registerfontmeta(lua_State *L);
+void pushfont(lua_State *L, Font *f);
+Font* checkfont(lua_State *L, int index);
+
+/* image */
+void registerimagemeta(lua_State *L);
+void pushimage(lua_State *L, Image *i);
+Image* checkimage(lua_State *L, int index);
+Image* optimage(lua_State *L, int index);
+
+/* geometry */
+void pushrect(lua_State *L, Rectangle r);
+Rectangle checkrect(lua_State *L, int index);
+void pushpoint(lua_State *L, Point p);
+Point checkpoint(lua_State *L, int index);
+Point getpoint(lua_State *L, int index);
+Point optpoint(lua_State *L, int index);
+
+/* libs */
+int openlibdraw(lua_State *L);
+int openlibkey(lua_State *L);
+
+#endif
--- a/lua9.c
+++ b/lua9.c
@@ -5,43 +5,15 @@
 #include <draw.h>
 #include <event.h>
 #include <keyboard.h>
-#include "lua.h"
-#include "lauxlib.h"
-#include "lualib.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include "ldraw.h"
+#include "utils.h"
 
-#define IMAGE_META "Image"
-#define DISPLAY_META "Display"
-#define FONT_META "Font"
-
-typedef struct ImagePtr ImagePtr;
-typedef struct DisplayPtr DisplayPtr;
-typedef struct FontPtr FontPtr;
-
-struct ImagePtr {
-	Image *p;
-};
-
-struct DisplayPtr {
-	Display *p;
-};
-
-struct FontPtr {
-	Font *p;
-};
-
 static lua_State *state;
 static int ridx, tidx;
 
-static ImagePtr* to_image(lua_State *L, Image *img) {
-	ImagePtr *i;
-
-	i = (ImagePtr*)lua_newuserdata(L, sizeof(ImagePtr));
-	luaL_getmetatable(L, IMAGE_META);
-	lua_setmetatable(L, -2);
-	i->p = img;
-	return i;
-}
-
 void eresized(int new) {
 	if(new && getwindow(display, Refnone) < 0){
 		fprintf(stderr, "cannot reattach to window: %r");
@@ -53,29 +25,9 @@
 	lua_pop(state, 2);
 }
 
-static void create_globals(lua_State *L) {
-	ImagePtr *i;
-	DisplayPtr *d;
-	FontPtr *f;
-
-	i = (ImagePtr*)lua_newuserdatauv(L, sizeof(ImagePtr), 1);
-	luaL_getmetatable(L, IMAGE_META);
-	lua_setmetatable(L, -2);
-	i->p = screen;
-	lua_setglobal(L, "screen");
-	d = (DisplayPtr*)lua_newuserdata(L, sizeof(DisplayPtr));
-	luaL_getmetatable(L, DISPLAY_META);
-	lua_setmetatable(L, -2);
-	d->p = display;
-	lua_setglobal(L, "display");
-	f = (FontPtr*)lua_newuserdata(L, sizeof(FontPtr));
-	luaL_getmetatable(L, FONT_META);
-	lua_setmetatable(L, -2);
-	f->p = font;
-	lua_setglobal(L, "font");
-}
-
-static int l_initdraw(lua_State *L) {
+static int
+linitdraw(lua_State *L) 
+{
 	const char *n;
 	char buf[256];
 	
@@ -96,11 +48,18 @@
 		lua_error(L);
 	}
 	state = L;
-	create_globals(L);
+	pushdisplay(L, display);
+	lua_setglobal(L, "display");
+	pushimage(L, screen);
+	lua_setglobal(L, "screen");
+	pushfont(L, font);
+	lua_setglobal(L, "font");
 	return 0;
 }
 
-static int l_einit(lua_State *L) {
+static int
+leinit(lua_State *L)
+{
 	lua_Integer i;
 
 	i = luaL_checknumber(L, -1);
@@ -108,7 +67,9 @@
 	return 0;
 }
 
-static int l_event(lua_State *L) {
+static int
+levent(lua_State *L)
+{
 	Event ev;
 	int e;
 
@@ -120,182 +81,97 @@
 	return 2;
 }
 
-static Point l_getpoint(lua_State *L, int index)
+static int
+ldraw(lua_State *L)
 {
-	Point p;
-
-	lua_pushstring(L, "x");
-	lua_gettable(L, index);
-	p.x = luaL_checkinteger(L, -1);
-	lua_pushstring(L, "y");
-	lua_gettable(L, index);
-	p.y = luaL_checkinteger(L, -1);
-	lua_pop(L, 2);
-	return p;
-}
-
-static Point l_checkpoint(lua_State *L, int index)
-{
-	if(lua_istable(L, index) == 0)
-		luaL_argerror(L, index, "draw: point table expected");
-	return l_getpoint(L, index);
-}
-
-static Point l_optpoint(lua_State *L, int index)
-{
-	if(lua_istable(L, index) == 0)
-		return ZP;
-	return l_getpoint(L, index);
-}
-
-static Rectangle l_getrect(lua_State *L, int index)
-{
-	Rectangle r;
-	int t;
-
-	lua_pushstring(L, "min");
-	lua_gettable(L, index);
-	lua_pushstring(L, "x");
-	lua_gettable(L, -2);
-	r.min.x = luaL_checkinteger(L, -1);
-	lua_pushstring(L, "y");
-	t = lua_gettable(L, -3);
-	r.min.y = luaL_checkinteger(L, -1);
-	lua_pop(L, 3); /* table | x | y */
-	lua_pushstring(L, "max");
-	lua_gettable(L, index);
-	lua_pushstring(L, "x");
-	lua_gettable(L, -2);
-	r.max.x = luaL_checkinteger(L, -1);
-	lua_pushstring(L, "y");
-	lua_gettable(L, -3);
-	r.max.y = luaL_checkinteger(L, -1);
-	lua_pop(L, 3);
-	return r;
-}
-
-static Rectangle l_checkrect(lua_State *L, int index)
-{
-	if(lua_istable(L, index) == 0)
-		luaL_argerror(L, index, "draw: rectangle table expected");
-	return l_getrect(L, index);
-}
-
-static Image* l_checkimage(lua_State *L, int index)
-{
-	ImagePtr *p;
-
-	p = (ImagePtr*)luaL_checkudata(L, index, IMAGE_META);
-	luaL_argcheck(L, p != NULL, index, "draw: Image expected");
-	return p->p;
-}
-
-static Image* l_optimage(lua_State *L, int index)
-{
-	if(lua_isnil(L, index))
-		return nil;
-	return l_checkimage(L, index);
-}
-
-static Font* l_checkfont(lua_State *L, int index)
-{
-	FontPtr *p;
-
-	p = (FontPtr*)luaL_checkudata(L, index, FONT_META);
-	luaL_argcheck(L, p != NULL, index, "draw: Font expected");
-	return p->p;
-}
-
-static Display* l_checkdisplay(lua_State *L, int index)
-{
-	DisplayPtr *p;
-
-	p = (DisplayPtr*)luaL_checkudata(L, index, DISPLAY_META);
-	luaL_argcheck(L, p!=NULL, index, "draw: Display expected");
-	return p->p;
-}
-
-static int l_draw(lua_State *L) {
 	Image *dst, *src, *mask;
 	Point p;
 	Rectangle r;
 
-	dst  = l_checkimage(L, 1);
-	r    = l_checkrect(L, 2);
-	src  = l_checkimage(L, 3);
-	mask = l_optimage(L, 4);
-	p    = l_checkpoint(L, 5);
+	dst  = checkimage(L, 1);
+	r    = checkrect(L, 2);
+	src  = checkimage(L, 3);
+	mask = optimage(L, 4);
+	p    = checkpoint(L, 5);
 	draw(dst, r, src, mask, p);
 	return 0;
 }
 
-static int l_line(lua_State *L) {
+static int
+lline(lua_State *L)
+{
 	Image *dst, *src;
 	Point p0, p1, sp;
 	int end0, end1, thick;
 
-	dst   = l_checkimage(L, 1);
-	p0    = l_checkpoint(L, 2);
-	p1    = l_checkpoint(L, 3);
+	dst   = checkimage(L, 1);
+	p0    = checkpoint(L, 2);
+	p1    = checkpoint(L, 3);
 	end0  = luaL_checkinteger(L, 4);
 	end1  = luaL_checkinteger(L, 5);
 	thick = luaL_checkinteger(L, 6);
-	src   = l_checkimage(L, 7);
-	sp    = l_checkpoint(L, 8);
+	src   = checkimage(L, 7);
+	sp    = checkpoint(L, 8);
 	line(dst, p0, p1, end0, end1, thick, src, sp);
 	return 0;
 }
 
-static int l_ellipse(lua_State *L)
+static int
+lellipse(lua_State *L)
 {
 	Image *dst, *src;
 	Point c, sp;
 	int a, b, thick;
 
-	dst   = l_checkimage(L, 1);
-	c     = l_checkpoint(L, 2);
+	dst   = checkimage(L, 1);
+	c     = checkpoint(L, 2);
 	a     = luaL_checkinteger(L, 3);
 	b     = luaL_checkinteger(L, 4);
 	thick = luaL_checkinteger(L, 5);
-	src   = l_checkimage(L, 6);
-	sp    = l_checkpoint(L, 7);
+	src   = checkimage(L, 6);
+	sp    = checkpoint(L, 7);
 	ellipse(dst, c, a, b, thick, src, sp);
 	return 0;
 }
 
-static int l_fillellipse(lua_State *L)
+static int
+lfillellipse(lua_State *L)
 {
 	Image *dst, *src;
 	Point c, sp;
 	int a, b;
 
-	dst   = l_checkimage(L, 1);
-	c     = l_checkpoint(L, 2);
+	dst   = checkimage(L, 1);
+	c     = checkpoint(L, 2);
 	a     = luaL_checkinteger(L, 3);
 	b     = luaL_checkinteger(L, 4);
-	src   = l_checkimage(L, 5);
-	sp    = l_checkpoint(L, 6);
+	src   = checkimage(L, 5);
+	sp    = checkpoint(L, 6);
 	fillellipse(dst, c, a, b, src, sp);
 	return 0;
 }
 
-static int l_string(lua_State *L) {
+static int
+lstring(lua_State *L)
+{
 	Image *dst, *src;
 	Font *f;
-	Point p, sp;
+	Point p, sp, r;
 	const char *s;
 
-	dst = l_checkimage(L, 1);
-	p   = l_checkpoint(L, 2);
-	src = l_checkimage(L, 3);
-	sp  = l_optpoint(L, 4);
-	f   = l_checkfont(L, 5);
+	dst = checkimage(L, 1);
+	p   = checkpoint(L, 2);
+	src = checkimage(L, 3);
+	sp  = optpoint(L, 4);
+	f   = checkfont(L, 5);
 	s   = luaL_checkstring(L, 6);
-	string(dst, p, src, sp, f, s);
-	return 0;
+	r   = string(dst, p, src, sp, f, s);
+	pushpoint(L, r);
+	return 1;
 }
 
-static int l_allocimage(lua_State *L)
+static int
+lallocimage(lua_State *L)
 {
 	Display *d;
 	Rectangle r;
@@ -303,207 +179,67 @@
 	int repl;
 	Image *i;
 
-	d    = l_checkdisplay(L, 1);
-	r    = l_checkrect(L, 2);
+	d    = checkdisplay(L, 1);
+	r    = checkrect(L, 2);
 	chan = (ulong)luaL_checkinteger(L, 3);
 	repl = luaL_checkinteger(L, 4);
 	col  = (ulong)luaL_checkinteger(L, 5);
 	i    = allocimage(d, r, chan, repl, col);
-	to_image(L, i);
+	pushimage(L, i);
 	return 1;
 }
 
-/* Image metatable */
-static int l_image_gc(lua_State *L) {
-	ImagePtr *i;
+static const struct luaL_Reg libdraw [] = {
+	{ "initdraw",    linitdraw },
+	{ "einit",       leinit },
+	{ "event",       levent },
+	{ "draw",        ldraw },
+	{ "line",        lline },
+	{ "ellipse",     lellipse },
+	{ "fillellipse", lfillellipse },
+	{ "string",      lstring },
+	{ "allocimage",  lallocimage },
+	{ NULL, NULL }
+};
 
-	i = (ImagePtr*)luaL_checkudata(L, 1, IMAGE_META);
-	luaL_argcheck(L, i != NULL, 1, "draw: Image expected");
-	if(i->p == screen) {
-		lua_pushboolean(L, 0);
-		return 1;
-	}
-	/* TODO freeimage */
-	lua_pushboolean(L, 1);
-	return 1;
-}
-
-static int l_image_tostring(lua_State *L) {
-	void *p;
-	char buf[64];
-
-	p = lua_touserdata(L, 1);
-	snprintf(buf, sizeof buf, "image: %p", p);
-	lua_pushstring(L, buf);
-	return 1;
-}
-
-static void l_pushrect(lua_State *L, Rectangle r)
+int
+openlibdraw(lua_State *L)
 {
-	lua_newtable(L);
-	lua_newtable(L);
-	lua_pushinteger(L, r.min.x);
-	lua_setfield(L, -2, "x");
-	lua_pushinteger(L, r.min.y);
-	lua_setfield(L, -2, "y");
-	lua_setfield(L, -2, "min");
-	lua_newtable(L);
-	lua_pushinteger(L, r.max.x);
-	lua_setfield(L, -2, "x");
-	lua_pushinteger(L, r.max.y);
-	lua_setfield(L, -2, "y");
-	lua_setfield(L, -2, "max");
-}
+	registerdisplaymeta(L);
+	registerimagemeta(L);
+	registerfontmeta(L);
+	luaL_newlib(L, libdraw);
+	pushglobal(L, "Emouse", Emouse);
+	pushglobal(L, "Ekeyboard", Ekeyboard);
+	pushglobal(L, "Endsquare", Endsquare);
+	pushglobal(L, "Enddisc", Enddisc);
+	pushglobal(L, "Endarrow", Endarrow);
+	pushglobal(L, "Endmask", Endmask);
 
-static int l_image_index(lua_State *L) {
-	Image *i;
-	const char *s;
-
-	i = l_checkimage(L, 1);
-	s = luaL_checkstring(L, 2);
-	if(!strncmp(s, "r", 1)) {
-		l_pushrect(L, i->r);
-	} else if(!strncmp(s, "clipr", 5)) {
-		l_pushrect(L, i->clipr);
-	} else if(!strncmp(s, "chan", 4)) {
-		lua_pushinteger(L, i->chan);
-	} else if(!strncmp(s, "depth", 5)) {
-		lua_pushinteger(L, i->depth);
-	} else if(!strncmp(s, "repl", 4)) {
-		lua_pushinteger(L, i->repl);
-	} else {
-		return 0;
-	}
 	return 1;
 }
 
-static const struct luaL_Reg image_funcs[] = {
-	{ "__gc", l_image_gc },
-	{ "__tostring", l_image_tostring },
-	{ "__index", l_image_index },
+static const luaL_Reg libs[] = {
+	{ "draw", openlibdraw },
+	{ "key",  openlibkey },
 	{ NULL, NULL },
 };
 
-static int l_display_gc(lua_State *L) {
-	/* we do not GC the display */
-	lua_pushboolean(L, 0);
-	return 1;
-}
-
-static int l_display_tostring(lua_State *L) {
-	void *p;
-	char buf[64];
-
-	p = lua_touserdata(L, 1);
-	snprintf(buf, sizeof buf, "display: %p", p);
-	lua_pushstring(L, buf);
-	return 1;
-}
-
-static int l_display_index(lua_State *L) {
-	DisplayPtr *d;
-	const char *s;
-
-	d = (DisplayPtr*)luaL_checkudata(L, 1, DISPLAY_META);
-	luaL_argcheck(L, d != NULL, 1, "draw: Display expected");
-	s = luaL_checkstring(L, 2);
-	if(strncmp(s, "white", 5) == 0) {
-		to_image(L, d->p->white);
-		return 1;
-	} else if(strncmp(s, "black", 5) == 0) {
-		to_image(L, d->p->black);
-		return 1;
-	}
-	return 0;
-}
-
-static const struct luaL_Reg display_funcs[] = {
-	{ "__gc", l_display_gc },
-	{ "__tostring", l_display_tostring },
-	{ "__index", l_display_index },
-	{ NULL, NULL },
-};
-
-static int l_font_gc(lua_State *L) {
-	/* TODO */
-	lua_pushboolean(L, 0);
-	return 1;
-}
-
-static int l_font_tostring(lua_State *L) {
-	void *p;
-
-	p = lua_touserdata(L, 1);
-	lua_pushfstring(L, "font: %p", p);
-	return 1;
-}
-
-static const struct luaL_Reg font_funcs[] = {
-	{ "__gc", l_font_gc },
-	{ "__tostring", l_font_tostring },
-//	{ "__index", l_display_index },
-	{ NULL, NULL },
-};
-
-static void create_metatable(lua_State *L, const char *name, luaL_Reg *funcs) {
-	luaL_newmetatable(L, name);
-	luaL_setfuncs(L, funcs, 0);
-	lua_pushliteral (L, "__metatable");
-	lua_pushliteral (L, "draw: you're not allowed to get this metatable");
-	lua_settable (L, -3);
-}
-
-static const struct luaL_Reg drawlib [] = {
-	{ "initdraw",    l_initdraw },
-	{ "einit",       l_einit },
-	{ "event",       l_event },
-	{ "draw",        l_draw },
-	{ "line",        l_line },
-	{ "ellipse",     l_ellipse },
-	{ "fillellipse", l_fillellipse },
-	{ "string",      l_string },
-	{ "allocimage",  l_allocimage },
-	{ NULL, NULL }
-};
-
-static void l_pushglobal(lua_State *L, const char *name, int value, int index)
-{
-	lua_pushnumber(L, value);
-	lua_setfield(L, index, name);	
-}
-
-int luaopen_drawlib (lua_State *L) {
-	create_metatable(L, IMAGE_META, image_funcs);
-	create_metatable(L, DISPLAY_META, display_funcs);
-	create_metatable(L, FONT_META, font_funcs);
-	luaL_newlib(L, drawlib);
-	lua_pushnumber(L, Emouse);
-	lua_setfield(L, -2, "Emouse");
-	lua_pushnumber(L, Ekeyboard);
-	lua_setfield(L, -2, "Ekeyboard");
-	l_pushglobal(L, "Endsquare", Endsquare, -2);
-	l_pushglobal(L, "Enddisc", Enddisc, -2);
-	l_pushglobal(L, "Endarrow", Endarrow, -2);
-	l_pushglobal(L, "Endmask", Endmask, -2);
-
-	return 1;
-}
-
-
 int
 main(int argc, char *argv[])
 {
 	lua_State *L;
+	luaL_Reg *lib;
 	char *f = NULL;
 	int r;
 
 	L = luaL_newstate();
 	luaL_openlibs(L);
-    	luaL_requiref(L, "draw", luaopen_drawlib, 1);
-    	lua_pop(L, 1);
-	if(argc > 1)
-		f = argv[1];
-	r = luaL_dofile(L, f);
+	for(lib = libs; lib->func; lib++){
+		luaL_requiref(L, lib->name, lib->func, 1);
+		lua_pop(L, 1);
+	}
+	r = luaL_dofile(L, argc > 1 ? argv[1] : NULL);
 	lua_close(L);
 	return f == LUA_OK;
 }
--- a/mkfile
+++ b/mkfile
@@ -6,13 +6,17 @@
 BIN=/$objtype/bin/ape
 
 OFILES=\
-    lua9.$O \
-    
+	display.$O \
+	font.$O \
+	image.$O \
+	geometry.$O \
+	key.$O \
+	utils.$O \
+	lua9.$O
+
 HFILES=\
-    /sys/include/ape/lauxlib.h \
-    /sys/include/ape/lua.h \
-    /sys/include/ape/luaconf.h \
-    /sys/include/ape/lualib.h
+	ldraw.h \
+	utils.h
 
 </sys/src/cmd/mkone
 
--- a/sample.lua
+++ b/sample.lua
@@ -31,7 +31,7 @@
 	if e == draw.Emouse then
 		--print 'Mouse event'
 	elseif e == draw.Ekeyboard then
-		if string.char(ev.kbdc) == 'q' then
+		if key.eq(ev.kbdc, 'q') or ev.kbdc == key.DEL then
 			os.exit()
 		end
 	end
--- /dev/null
+++ b/utils.c
@@ -1,0 +1,21 @@
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+/* push a global definition in the lib on the stack */
+void
+pushglobal(lua_State *L, const char *name, int value)
+{
+	lua_pushnumber(L, value);
+	lua_setfield(L, -2, name);	
+}
+
+void
+createmetatable(lua_State *L, const char *name, luaL_Reg *funcs)
+{
+	luaL_newmetatable(L, name);
+	luaL_setfuncs(L, funcs, 0);
+	lua_pushliteral (L, "__metatable");
+	lua_pushliteral (L, "metatable access forbidden");
+	lua_settable (L, -3);
+}
--- /dev/null
+++ b/utils.h
@@ -1,0 +1,7 @@
+#ifndef UTILS_H__
+#define UTILS_H__
+
+void pushglobal(lua_State *L, const char *name, int value);
+void createmetatable(lua_State *L, const char *name, luaL_Reg *funcs);
+
+#endif