59d88a15eba019f37b72fd6b8ccbb3dc0d7b530b
[project/luci.git] / libs / lmo / src / lmo_lualib.c
1 /*
2 * lmo - Lua Machine Objects - Lua binding
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "lmo_lualib.h"
20
21 extern char _lmo_error[1024];
22
23
24 static int lmo_L_open(lua_State *L) {
25 const char *filename = luaL_checklstring(L, 1, NULL);
26 lmo_archive_t *ar, **udata;
27
28 if( (ar = lmo_open(filename)) != NULL )
29 {
30 if( (udata = lua_newuserdata(L, sizeof(lmo_archive_t *))) != NULL )
31 {
32 *udata = ar;
33 luaL_getmetatable(L, LMO_ARCHIVE_META);
34 lua_setmetatable(L, -2);
35 return 1;
36 }
37
38 lmo_close(ar);
39 lua_pushnil(L);
40 lua_pushstring(L, "out of memory");
41 return 2;
42 }
43
44 lua_pushnil(L);
45 lua_pushstring(L, lmo_error());
46 return 2;
47 }
48
49 static int lmo_L_hash(lua_State *L) {
50 const char *data = luaL_checkstring(L, 1);
51 uint32_t hash = sfh_hash(data, strlen(data));
52 lua_pushinteger(L, (lua_Integer)hash);
53 return 1;
54 }
55
56 static lmo_luaentry_t *_lmo_push_entry(lua_State *L) {
57 lmo_luaentry_t *le;
58
59 if( (le = lua_newuserdata(L, sizeof(lmo_luaentry_t))) != NULL )
60 {
61 luaL_getmetatable(L, LMO_ENTRY_META);
62 lua_setmetatable(L, -2);
63
64 return le;
65 }
66
67 return NULL;
68 }
69
70 static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) {
71 lmo_entry_t *e = ar->index;
72 lmo_luaentry_t *le = NULL;
73
74 while( e != NULL )
75 {
76 if( e->key_id == hash )
77 {
78 if( (le = _lmo_push_entry(L)) != NULL )
79 {
80 le->archive = ar;
81 le->entry = e;
82 return 1;
83 }
84 else
85 {
86 lua_pushnil(L);
87 lua_pushstring(L, "out of memory");
88 return 2;
89 }
90 }
91
92 e = e->next;
93 }
94
95 lua_pushnil(L);
96 return 1;
97 }
98
99 static int lmo_L_get(lua_State *L) {
100 lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
101 uint32_t hash = (uint32_t) luaL_checkinteger(L, 2);
102 return _lmo_lookup(L, *ar, hash);
103 }
104
105 static int lmo_L_lookup(lua_State *L) {
106 lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
107 const char *key = luaL_checkstring(L, 2);
108 uint32_t hash = sfh_hash(key, strlen(key));
109 return _lmo_lookup(L, *ar, hash);
110 }
111
112 static int lmo_L_foreach(lua_State *L) {
113 lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
114 lmo_entry_t *e = (*ar)->index;
115
116 if( lua_isfunction(L, 2) )
117 {
118 while( e != NULL )
119 {
120 lua_pushvalue(L, 2);
121 lua_pushinteger(L, e->key_id);
122 lua_pushlstring(L, &(*ar)->mmap[e->offset], e->length);
123 lua_pcall(L, 2, 0, 0);
124 e = e->next;
125 }
126 }
127
128 return 0;
129 }
130
131 static int lmo_L__gc(lua_State *L) {
132 lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
133
134 if( (*ar) != NULL )
135 lmo_close(*ar);
136
137 *ar = NULL;
138
139 return 0;
140 }
141
142 static int lmo_L__tostring(lua_State *L) {
143 lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
144 lua_pushfstring(L, "LMO Archive (%d bytes)", (*ar)->length);
145 return 1;
146 }
147
148
149 static int _lmo_convert_entry(lua_State *L, int idx) {
150 lmo_luaentry_t *le = luaL_checkudata(L, idx, LMO_ENTRY_META);
151
152 lua_pushlstring(L,
153 &le->archive->mmap[le->entry->offset],
154 le->entry->length
155 );
156
157 return 1;
158 }
159
160 static int lmo_L_entry__tostring(lua_State *L) {
161 return _lmo_convert_entry(L, 1);
162 }
163
164 static int lmo_L_entry__concat(lua_State *L) {
165 if( lua_isuserdata(L, 1) )
166 _lmo_convert_entry(L, 1);
167 else
168 lua_pushstring(L, lua_tostring(L, 1));
169
170 if( lua_isuserdata(L, 2) )
171 _lmo_convert_entry(L, 2);
172 else
173 lua_pushstring(L, lua_tostring(L, 2));
174
175 lua_concat(L, 2);
176
177 return 1;
178 }
179
180 static int lmo_L_entry__len(lua_State *L) {
181 lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
182 lua_pushinteger(L, le->entry->length);
183 return 1;
184 }
185
186 static int lmo_L_entry__gc(lua_State *L) {
187 lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
188 le->archive = NULL;
189 le->entry = NULL;
190 return 0;
191 }
192
193
194 /* lmo method table */
195 static const luaL_reg M[] = {
196 {"close", lmo_L__gc},
197 {"get", lmo_L_get},
198 {"lookup", lmo_L_lookup},
199 {"foreach", lmo_L_foreach},
200 {"__tostring", lmo_L__tostring},
201 {"__gc", lmo_L__gc},
202 {NULL, NULL}
203 };
204
205 /* lmo.entry method table */
206 static const luaL_reg E[] = {
207 {"__tostring", lmo_L_entry__tostring},
208 {"__concat", lmo_L_entry__concat},
209 {"__len", lmo_L_entry__len},
210 {"__gc", lmo_L_entry__gc},
211 {NULL, NULL}
212 };
213
214 /* module table */
215 static const luaL_reg R[] = {
216 {"open", lmo_L_open},
217 {"hash", lmo_L_hash},
218 {NULL, NULL}
219 };
220
221 LUALIB_API int luaopen_lmo(lua_State *L) {
222 luaL_newmetatable(L, LMO_ARCHIVE_META);
223 luaL_register(L, NULL, M);
224 lua_pushvalue(L, -1);
225 lua_setfield(L, -2, "__index");
226 lua_setglobal(L, LMO_ARCHIVE_META);
227
228 luaL_newmetatable(L, LMO_ENTRY_META);
229 luaL_register(L, NULL, E);
230 lua_pushvalue(L, -1);
231 lua_setfield(L, -2, "__index");
232 lua_setglobal(L, LMO_ENTRY_META);
233
234 luaL_register(L, LMO_LUALIB_META, R);
235
236 return 1;
237 }