1/*=========================================================================*\
2* Simple exception support
3* LuaSocket toolkit
4\*=========================================================================*/
5#include <stdio.h>
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "except.h"
12
13#if LUA_VERSION_NUM < 502
14#define lua_pcallk(L, na, nr, err, ctx, cont) \
15 (((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
16#endif
17
18#if LUA_VERSION_NUM < 503
19typedef int lua_KContext;
20#endif
21
22/*=========================================================================*\
23* Internal function prototypes.
24\*=========================================================================*/
25static int global_protect(lua_State *L);
26static int global_newtry(lua_State *L);
27static int protected_(lua_State *L);
28static int finalize(lua_State *L);
29static int do_nothing(lua_State *L);
30
31/* except functions */
32static luaL_Reg func[] = {
33 {"newtry", global_newtry},
34 {"protect", global_protect},
35 {NULL, NULL}
36};
37
38/*-------------------------------------------------------------------------*\
39* Try factory
40\*-------------------------------------------------------------------------*/
41static void wrap(lua_State *L) {
42 lua_createtable(L, 1, 0);
43 lua_pushvalue(L, -2);
44 lua_rawseti(L, -2, 1);
45 lua_pushvalue(L, lua_upvalueindex(1));
46 lua_setmetatable(L, -2);
47}
48
49static int finalize(lua_State *L) {
50 if (!lua_toboolean(L, 1)) {
51 lua_pushvalue(L, lua_upvalueindex(2));
52 lua_call(L, 0, 0);
53 lua_settop(L, 2);
54 wrap(L);
55 lua_error(L);
56 return 0;
57 } else return lua_gettop(L);
58}
59
60static int do_nothing(lua_State *L) {
61 (void) L;
62 return 0;
63}
64
65static int global_newtry(lua_State *L) {
66 lua_settop(L, 1);
67 if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
68 lua_pushvalue(L, lua_upvalueindex(1));
69 lua_insert(L, -2);
70 lua_pushcclosure(L, finalize, 2);
71 return 1;
72}
73
74/*-------------------------------------------------------------------------*\
75* Protect factory
76\*-------------------------------------------------------------------------*/
77static int unwrap(lua_State *L) {
78 if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
79 int r = lua_rawequal(L, -1, lua_upvalueindex(1));
80 lua_pop(L, 1);
81 if (r) {
82 lua_pushnil(L);
83 lua_rawgeti(L, -2, 1);
84 return 1;
85 }
86 }
87 return 0;
88}
89
90static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
91 (void)ctx;
92 if (status != 0 && status != LUA_YIELD) {
93 if (unwrap(L)) return 2;
94 else return lua_error(L);
95 } else return lua_gettop(L);
96}
97
98#if LUA_VERSION_NUM == 502
99static int protected_cont(lua_State *L) {
100 int ctx = 0;
101 int status = lua_getctx(L, &ctx);
102 return protected_finish(L, status, ctx);
103}
104#else
105#define protected_cont protected_finish
106#endif
107
108static int protected_(lua_State *L) {
109 int status;
110 lua_pushvalue(L, lua_upvalueindex(2));
111 lua_insert(L, 1);
112 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
113 return protected_finish(L, status, 0);
114}
115
116static int global_protect(lua_State *L) {
117 lua_settop(L, 1);
118 lua_pushvalue(L, lua_upvalueindex(1));
119 lua_insert(L, 1);
120 lua_pushcclosure(L, protected_, 2);
121 return 1;
122}
123
124/*-------------------------------------------------------------------------*\
125* Init module
126\*-------------------------------------------------------------------------*/
127int except_open(lua_State *L) {
128 lua_newtable(L); /* metatable for wrapped exceptions */
129 lua_pushboolean(L, 0);
130 lua_setfield(L, -2, "__metatable");
131 luaL_setfuncs(L, func, 1);
132 return 0;
133}
134