blob: 85451b08f203d6f30fca374ce7dbf0e0f13b5a24 [file] [log] [blame]
Thierry Fournierfb0b5462016-01-21 09:28:58 +01001/* All the functions in this file runs with aLua stack, and can
2 * return with a longjmp. All of these function must be launched
3 * in an environment able to catch a longjmp, otherwise a
4 * critical error can be raised.
5 */
6#include <lauxlib.h>
7#include <lua.h>
8#include <lualib.h>
9
Thierry Fournierb1f46562016-01-21 09:46:15 +010010#include <common/time.h>
11
Thierry Fournier1de16592016-01-27 09:49:07 +010012/* Contains the class reference of the concat object. */
13static int class_concat_ref;
14
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010015/* Return an object of the expected type, or throws an error. */
16void *hlua_checkudata(lua_State *L, int ud, int class_ref)
17{
18 void *p;
Thierry Fournier53518272016-01-27 10:34:09 +010019 int ret;
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010020
21 /* Check if the stack entry is an array. */
22 if (!lua_istable(L, ud))
Thierry Fournier53518272016-01-27 10:34:09 +010023 luaL_argerror(L, ud, NULL);
24
25 /* pop the metatable of the referencecd object. */
26 if (!lua_getmetatable(L, ud))
27 luaL_argerror(L, ud, NULL);
28
29 /* pop the expected metatable. */
30 lua_rawgeti(L, LUA_REGISTRYINDEX, class_ref);
31
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010032 /* Check if the metadata have the expected type. */
Thierry Fournier53518272016-01-27 10:34:09 +010033 ret = lua_rawequal(L, -1, -2);
34 lua_pop(L, 2);
35 if (!ret)
36 luaL_argerror(L, ud, NULL);
37
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010038 /* Push on the stack at the entry [0] of the table. */
39 lua_rawgeti(L, ud, 0);
Thierry Fournier53518272016-01-27 10:34:09 +010040
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010041 /* Check if this entry is userdata. */
42 p = lua_touserdata(L, -1);
43 if (!p)
Thierry Fournier53518272016-01-27 10:34:09 +010044 luaL_argerror(L, ud, NULL);
45
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010046 /* Remove the entry returned by lua_rawgeti(). */
47 lua_pop(L, 1);
Thierry Fournier53518272016-01-27 10:34:09 +010048
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +010049 /* Return the associated struct. */
50 return p;
51}
52
Thierry Fournierb1f46562016-01-21 09:46:15 +010053/* This function return the current date at epoch format in milliseconds. */
54int hlua_now(lua_State *L)
55{
56 lua_newtable(L);
57 lua_pushstring(L, "sec");
58 lua_pushinteger(L, now.tv_sec);
59 lua_rawset(L, -3);
60 lua_pushstring(L, "usec");
61 lua_pushinteger(L, now.tv_usec);
62 lua_rawset(L, -3);
63 return 1;
64}
65
Thierry Fournier1550d5d2016-01-21 09:35:41 +010066/* This functions expects a Lua string as HTTP date, parse it and
67 * returns an integer containing the epoch format of the date, or
68 * nil if the parsing fails.
69 */
70static int hlua_parse_date(lua_State *L, int (*fcn)(const char *, int, struct tm*))
71{
72 const char *str;
73 size_t len;
74 struct tm tm;
75 time_t time;
76
77 str = luaL_checklstring(L, 1, &len);
78
79 if (!fcn(str, len, &tm)) {
80 lua_pushnil(L);
81 return 1;
82 }
83
84 /* This function considers the content of the broken-down time
85 * is exprimed in the UTC timezone. timegm don't care about
86 * the gnu variable tm_gmtoff. If gmtoff is set, or if you know
87 * the timezone from the broken-down time, it must be fixed
88 * after the conversion.
89 */
90 time = timegm(&tm);
91 if (time == -1) {
92 lua_pushnil(L);
93 return 1;
94 }
95
96 lua_pushinteger(L, (int)time);
97 return 1;
98}
99static int hlua_http_date(lua_State *L)
100{
101 return hlua_parse_date(L, parse_http_date);
102}
103static int hlua_imf_date(lua_State *L)
104{
105 return hlua_parse_date(L, parse_imf_date);
106}
107static int hlua_rfc850_date(lua_State *L)
108{
109 return hlua_parse_date(L, parse_rfc850_date);
110}
111static int hlua_asctime_date(lua_State *L)
112{
113 return hlua_parse_date(L, parse_asctime_date);
114}
115
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100116static void hlua_array_add_fcn(lua_State *L, const char *name,
117 int (*function)(lua_State *L))
118{
119 lua_pushstring(L, name);
120 lua_pushcclosure(L, function, 0);
121 lua_rawset(L, -3);
122}
123
Thierry Fournier1de16592016-01-27 09:49:07 +0100124static luaL_Buffer *hlua_check_concat(lua_State *L, int ud)
125{
126 return (luaL_Buffer *)(hlua_checkudata(L, ud, class_concat_ref));
127}
128
129static int hlua_concat_add(lua_State *L)
130{
131 luaL_Buffer *b;
132 const char *str;
133 size_t l;
134
135 /* First arg must be a concat object. */
136 b = hlua_check_concat(L, 1);
137
138 /* Second arg must be a string. */
139 str = luaL_checklstring(L, 2, &l);
140
141 luaL_addlstring(b, str, l);
142 return 0;
143}
144
145static int hlua_concat_dump(lua_State *L)
146{
147 luaL_Buffer *b;
148
149 /* First arg must be a concat object. */
150 b = hlua_check_concat(L, 1);
151
152 /* Push the soncatenated strng in the stack. */
153 luaL_pushresult(b);
154 return 1;
155}
156
157int hlua_concat_new(lua_State *L)
158{
159 luaL_Buffer *b;
160
161 lua_newtable(L);
162 b = lua_newuserdata(L, sizeof(luaL_Buffer));
163 lua_rawseti(L, -2, 0);
164
165 lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
166 lua_setmetatable(L, -2);
167
168 luaL_buffinit(L, b);
169 return 1;
170}
171
172static int concat_tostring(lua_State *L)
173{
174 const void *ptr = lua_topointer(L, 1);
175 lua_pushfstring(L, "Concat object: %p", ptr);
176 return 1;
177}
178
179static int hlua_concat_init(lua_State *L)
180{
181 /* Creates the buffered concat object. */
182 lua_newtable(L);
183
184 lua_pushstring(L, "__tostring");
185 lua_pushcclosure(L, concat_tostring, 0);
186 lua_settable(L, -3);
187
188 lua_pushstring(L, "__index"); /* Creates the index entry. */
189 lua_newtable(L); /* The "__index" content. */
190
191 lua_pushstring(L, "add");
192 lua_pushcclosure(L, hlua_concat_add, 0);
193 lua_settable(L, -3);
194
195 lua_pushstring(L, "dump");
196 lua_pushcclosure(L, hlua_concat_dump, 0);
197 lua_settable(L, -3);
198
199 lua_settable(L, -3); /* Sets the __index entry. */
200 class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
201
202 return 1;
203}
204
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100205int hlua_fcn_reg_core_fcn(lua_State *L)
206{
Thierry Fournier1de16592016-01-27 09:49:07 +0100207 if (!hlua_concat_init(L))
208 return 0;
209
Thierry Fournierb1f46562016-01-21 09:46:15 +0100210 hlua_array_add_fcn(L, "now", hlua_now);
Thierry Fournier1550d5d2016-01-21 09:35:41 +0100211 hlua_array_add_fcn(L, "http_date", hlua_http_date);
212 hlua_array_add_fcn(L, "imf_date", hlua_imf_date);
213 hlua_array_add_fcn(L, "rfc850_date", hlua_rfc850_date);
214 hlua_array_add_fcn(L, "asctime_date", hlua_asctime_date);
Thierry Fournier1de16592016-01-27 09:49:07 +0100215 hlua_array_add_fcn(L, "concat", hlua_concat_new);
Thierry Fournier1550d5d2016-01-21 09:35:41 +0100216 return 5;
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100217}