shithub: lu9-p9

Download patch

ref: 4d4deaa134b151e364f06c5731790b23dcd35233
parent: 68af611454400ea7ef8617c7c8b35d817e9caa50
author: kvik <kvik@a-b.xyz>
date: Thu Apr 15 15:05:47 EDT 2021

p9: implement non-throwing error reporting

--- a/fs.c
+++ b/fs.c
@@ -8,7 +8,7 @@
 	file = luaL_checkstring(L, 1);
 	mode = luaL_checkinteger(L, 2);
 	if((fd = open(file, mode)) == -1)
-		lerror(L, "open");
+		return error(L, "open: %r");
 	lua_pushinteger(L, fd);
 	return 1;
 }
@@ -24,7 +24,7 @@
 	mode = luaL_checkinteger(L, 2);
 	perm = luaL_checkinteger(L, 3);
 	if((fd = create(file, mode, perm)) == -1)
-		lerror(L, "create");
+		return error(L, "create: %r");
 	lua_pushinteger(L, fd);
 	return 1;
 }
@@ -33,7 +33,7 @@
 p9_close(lua_State *L)
 {
 	if(close(luaL_checkinteger(L, 1)) == -1)
-		lerror(L, "close");
+		return error(L, "close: %r");
 	return 0;
 }
 
@@ -53,7 +53,7 @@
 	else
 		n = pread(fd, buf, nbytes, offset);
 	if(n == -1)
-		lerror(L, "read");
+		return error(L, "read: %r");
 	lua_pushlstring(L, buf, n);
 	return 1;
 }
@@ -75,7 +75,7 @@
 	else
 		n = pwrite(fd, buf, nbytes, offset);
 	if(n != nbytes)
-		lerror(L, "write");
+		return error(L, "write: %r");
 	lua_pushinteger(L, n);
 	return 1;
 }
@@ -90,7 +90,7 @@
 	n = luaL_checkinteger(L, 2);
 	type = luaL_checkinteger(L, 3);
 	if((off = seek(fd, n, type)) == -1)
-		lerror(L, "seek");
+		return error(L, "seek: %r");
 	lua_pushinteger(L, off);
 	return 1;
 }
@@ -102,7 +102,7 @@
 	
 	file = luaL_checkstring(L, 1);
 	if(remove(file) == -1)
-		lerror(L, "remove");
+		return error(L, "remove: %r");
 	lua_pushboolean(L, 1);
 	return 1;
 }
@@ -116,7 +116,7 @@
 	fd = luaL_checkinteger(L, 1);
 	buf = getbuffer(L, 8192);
 	if(fd2path(fd, buf, 8192) != 0)
-		lerror(L, "fd2path");
+		return error(L, "fd2path: %r");
 	lua_pushstring(L, buf);
 	return 1;
 }
@@ -198,12 +198,8 @@
 	case LUA_TNUMBER:
 		d = dirfstat(lua_tonumber(L, 1)); break;
 	}
-	if(d == nil){
-		lua_pushnil(L);
-		seterror(L, "stat: %r");
-		pusherror(L);
-		return 2;
-	}
+	if(d == nil)
+		return error(L, "stat: %r");
 	createdirtable(L, d);
 	free(d);
 	return 1;
@@ -220,54 +216,51 @@
 {
 	static int p9_walkout(lua_State*);
 	static int p9_walknext(lua_State*);
-	int nargs;
+	int nargs, wstate;
 	Dir *d;
 	Walk *w;
 	
 	nargs = lua_gettop(L);
 	w = lua_newuserdatauv(L, sizeof(Walk), 1);
+	wstate = nargs + 1;
 	w->fd = -1;
 	w->nleft = 0;
 	w->dirs = w->p = nil;
 	luaL_setmetatable(L, "p9-Walk");
 	if(nargs == 2){
-		lua_insert(L, 2);
-		lua_setiuservalue(L, -2, 1);
+		lua_pushvalue(L, 2);
+		lua_setiuservalue(L, wstate, 1);
 	}
 	if(lua_isnumber(L, 1))
 		w->fd = lua_tointeger(L, 1);
 	else{
 		if((w->fd = open(luaL_checkstring(L, 1), OREAD|OCEXEC)) == -1){
-			seterror(L, "open: %r");
+			error(L, "open: %r");
 			goto Error;
 		}
 	}
 	if((d = dirfstat(w->fd)) == nil){
-		seterror(L, "stat: %r");
+		error(L, "stat: %r");
 		goto Error;
 	}
 	int isdir = d->mode & DMDIR;
 	free(d);
 	if(!isdir){
-		seterror(L, "walk in a non-directory");
+		error(L, "walk in a non-directory");
 		goto Error;
 	}
 	/* return p9_walknext, p9-Walk, nil, p9-Walk */
-	int i = lua_gettop(L);
 	lua_pushcfunction(L, p9_walknext);
-	lua_pushvalue(L, i);
+	lua_pushvalue(L, wstate);
 	lua_pushnil(L);
-	lua_pushvalue(L, i);
+	lua_pushvalue(L, wstate);
 	return 4;
 Error:
-	lua_getiuservalue(L, -1, 1);
-	if(lua_istable(L, -1)){
-		pusherror(L);
-		lua_setfield(L, -2, "error");
+	if(nargs == 2){
+		lua_setfield(L, 2, "error");
 		lua_pushcfunction(L, p9_walkout);
 		return 1;
 	}
-	pusherror(L);
 	return lua_error(L);
 }
 
@@ -290,7 +283,7 @@
 			w->dirs = nil;
 		}
 		if((w->nleft = dirread(w->fd, &w->dirs)) == -1){
-			seterror(L, "dirread: %r");
+			error(L, "dirread: %r");
 			goto Error;
 		}
 		w->p = w->dirs;
@@ -302,13 +295,14 @@
 	createdirtable(L, d);
 	return 1;
 Error:
-	pusherror(L);
-	if(lua_istable(L, lua_upvalueindex(1))){
-		lua_setfield(L, lua_upvalueindex(1), "error");
+	if(lua_getiuservalue(L, 1, 1) == LUA_TTABLE){
+		lua_pushvalue(L, -2);
+		lua_setfield(L, -2, "error");
 		lua_pushnil(L);
 		return 1;
 	}
-	return lua_error(L);
+	lua_pop(L, 1);
+	return 2;
 }
 
 static int
@@ -317,10 +311,14 @@
 	Walk *w;
 	
 	w = luaL_checkudata(L, 1, "p9-Walk");
-	free(w->dirs);
-	w->dirs = nil;
-	close(w->fd);
-	w->fd = -1;
+	if(w->dirs != nil){
+		free(w->dirs);
+		w->dirs = nil;
+	}
+	if(w->fd != -1){
+		close(w->fd);
+		w->fd = -1;
+	}
 	return 0;
 }
 
--- a/mod/init.lua
+++ b/mod/init.lua
@@ -413,41 +413,4 @@
 	end,
 })
 
-
-
-
--- Lethal API
--- p9.lethal() returns a proxy table that is just like the
--- regular p9 module table, except that each function field
--- is wrapped such that any error raised during a call
--- results in program termination. An error is printed to
--- fd 2 and the same error is used for the program's exit status.
--- Note that this only mechanism only works for the fields
--- of the p9 module, like the p9.open and friends.
--- In particular, it doesn't apply to methods of File objects
--- nor to the p9.env object.
--- This limitation should be removed in the future.
-
-local lethalproxy = setmetatable({}, {
-	__index = function(_, key)
-		if type(p9[key]) ~= "function" then
-			return p9[key]
-		end
-		return function(...)
-			local res = table.pack(pcall(p9[key], ...))
-			if not res[1] then
-				p9.write(2, string.format("%s: %s\n", arg[0] or "lua", res[2]))
-				os.exit(res[2])
-			end
-			table.remove(res, 1)
-			return table.unpack(res)
-		end
-	end
-})
-
---- lethal() -> p9{}
-function p9.lethal()
-	return lethalproxy
-end
-
 return p9
--- a/ns.c
+++ b/ns.c
@@ -9,7 +9,7 @@
 	over = luaL_checkstring(L, 2);
 	flag = luaL_checkinteger(L, 3);
 	if((r = bind(this, over, flag)) == -1)
-		lerror(L, "bind");
+		return error(L, "bind: %r");
 	lua_pushinteger(L, r);
 	return 1;
 }
@@ -26,7 +26,7 @@
 	flag = luaL_checkinteger(L, 4);
 	aname = luaL_checkstring(L, 5);
 	if((r = mount(fd, afd, over, flag, aname)) == -1)
-		lerror(L, "mount");
+		return error(L, "mount: %r");
 	lua_pushinteger(L, r);
 	return 1;
 }
@@ -40,7 +40,7 @@
 	name = luaL_optstring(L, 1, nil);
 	over = luaL_checkstring(L, 2);
 	if((r = unmount(name, over)) == -1)
-		lerror(L, "unmount");
+		return error(L, "unmount: %r");
 	lua_pushinteger(L, r);
 	return 1;
 }
--- a/p9.c
+++ b/p9.c
@@ -5,8 +5,8 @@
 #include <lua.h>
 #include <lauxlib.h>
 
-static void
-seterror(lua_State *L, char *fmt, ...)
+static int
+error(lua_State *L, char *fmt, ...)
 {
 	va_list varg;
 	int n;
@@ -13,29 +13,13 @@
 	char *buf;
 	luaL_Buffer b;
 	
+	lua_pushnil(L);
 	buf = luaL_buffinitsize(L, &b, 512);
 	va_start(varg, fmt);
 	n = vsnprint(buf, 512, fmt, varg);
 	va_end(varg);
 	luaL_pushresultsize(&b, n);
-	lua_setfield(L, LUA_REGISTRYINDEX, "p9-error");
-}
-
-static const char*
-pusherror(lua_State *L)
-{
-	lua_getfield(L, LUA_REGISTRYINDEX, "p9-error");
-	return lua_tostring(L, -1);
-}
-
-static void
-lerror(lua_State *L, char *call)
-{
-	char err[ERRMAX];
-	
-	rerrstr(err, sizeof err);
-	lua_pushfstring(L, "%s: %s", call, err);
-	lua_error(L);
+	return 2;
 }
 
 /* Memory allocator associated with Lua state */
--- a/proc.c
+++ b/proc.c
@@ -6,7 +6,7 @@
 	
 	flags = luaL_checkinteger(L, 1);
 	if((r = rfork(flags)) == -1)
-		lerror(L, "rfork");
+		return error(L, "rfork %r");
 	lua_pushinteger(L, r);
 	return 1;
 }
--- a/test.lua
+++ b/test.lua
@@ -75,7 +75,7 @@
 	local f <close> = p9.createfile(tmp())
 	fd = f.fd
 end
-assert(pcall(p9.seek, fd, 0) == false)
+assert(p9.seek(fd, 0) == nil)
 -- Make sure it's not closed
 local fd
 do
@@ -82,7 +82,7 @@
 	local f = p9.createfile(tmp())
 	fd = f.fd
 end
-assert(pcall(p9.seek, fd, 0) == true)
+assert(p9.seek(fd, 0))
 p9.close(fd)
 
 -- Basic operations. These are the same as regular
@@ -173,18 +173,18 @@
 
 -- Namespaces
 -- bind and unmount work
-assert(pcall(function()
+assert(function()
 	local f
-	p9.bind("#|", "/n/pipe")
-	f = p9.openfile("/n/pipe/data")
-	p9.unmount("/n/pipe")
-	assert(pcall(p9.openfile, "/n/pipe/data") == false)
-end))
+	assert(p9.bind("#|", "/n/pipe"))
+	f = assert(p9.openfile("/n/pipe/data"))
+	assert(p9.unmount("/n/pipe"))
+	assert(p9.openfile("/n/pipe/data") == nil)
+end)
 -- mount works
-assert(pcall(function()
+assert(function()
 	assert(p9.mount(p9.open("/srv/cwfs", "rw"), nil, "/n/test"))
 	assert(p9.openfile("/n/test/lib/glass"))
-end))
+end)
 
 
 -- Process control