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