1 /*=========================================================================*\
2 * Simple exception support
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <stdio.h>
6
7 #include "lua.h"
8 #include "lauxlib.h"
9
10 #include "except.h"
11
12 /*=========================================================================*\
13 * Internal function prototypes.
14 \*=========================================================================*/
15 static int global_protect(lua_State *L);
16 static int global_newtry(lua_State *L);
17 static int protected_(lua_State *L);
18 static int finalize(lua_State *L);
19 static int do_nothing(lua_State *L);
20
21 /* except functions */
22 static luaL_Reg func[] = {
23 {"newtry", global_newtry},
24 {"protect", global_protect},
25 {NULL, NULL}
26 };
27
28 /*-------------------------------------------------------------------------*\
29 * Try factory
30 \*-------------------------------------------------------------------------*/
wrap(lua_State * L)31 static void wrap(lua_State *L) {
32 lua_newtable(L);
33 lua_pushnumber(L, 1);
34 lua_pushvalue(L, -3);
35 lua_settable(L, -3);
36 lua_insert(L, -2);
37 lua_pop(L, 1);
38 }
39
finalize(lua_State * L)40 static int finalize(lua_State *L) {
41 if (!lua_toboolean(L, 1)) {
42 lua_pushvalue(L, lua_upvalueindex(1));
43 lua_pcall(L, 0, 0, 0);
44 lua_settop(L, 2);
45 wrap(L);
46 lua_error(L);
47 return 0;
48 } else return lua_gettop(L);
49 }
50
do_nothing(lua_State * L)51 static int do_nothing(lua_State *L) {
52 (void) L;
53 return 0;
54 }
55
global_newtry(lua_State * L)56 static int global_newtry(lua_State *L) {
57 lua_settop(L, 1);
58 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
59 lua_pushcclosure(L, finalize, 1);
60 return 1;
61 }
62
63 /*-------------------------------------------------------------------------*\
64 * Protect factory
65 \*-------------------------------------------------------------------------*/
unwrap(lua_State * L)66 static int unwrap(lua_State *L) {
67 if (lua_istable(L, -1)) {
68 lua_pushnumber(L, 1);
69 lua_gettable(L, -2);
70 lua_pushnil(L);
71 lua_insert(L, -2);
72 return 1;
73 } else return 0;
74 }
75
protected_(lua_State * L)76 static int protected_(lua_State *L) {
77 lua_pushvalue(L, lua_upvalueindex(1));
78 lua_insert(L, 1);
79 if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
80 if (unwrap(L)) return 2;
81 else lua_error(L);
82 return 0;
83 } else return lua_gettop(L);
84 }
85
global_protect(lua_State * L)86 static int global_protect(lua_State *L) {
87 lua_pushcclosure(L, protected_, 1);
88 return 1;
89 }
90
91 /*-------------------------------------------------------------------------*\
92 * Init module
93 \*-------------------------------------------------------------------------*/
except_open(lua_State * L)94 int except_open(lua_State *L) {
95 luaL_openlib(L, NULL, func, 0);
96 return 0;
97 }
98