ade8e01f72321a0c210788239f3dc633fc89e3b9
[project/luci.git] / libs / lmo / src / lmo_lualib.c
1 /*
2  * lmo - Lua Machine Objects - Lua binding
3  *
4  *   Copyright (C) 2009-2012 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 uint32_t _lmo_hash_string(lua_State *L, int n) {
50         size_t len;
51         const char *str = luaL_checklstring(L, n, &len);
52         char res[4096];
53         char *ptr, prev;
54
55         if (!str || len >= sizeof(res))
56                 return 0;
57
58         while (*str && isspace(*str))
59                 str++;
60
61         for (prev = 0, ptr = res; *str; prev = *str, str++)
62         {
63                 if (isspace(*str))
64                 {
65                         if (isspace(prev))
66                                 continue;
67
68                         *ptr++ = ' ';
69                 }
70                 else
71                 {
72                         *ptr++ = *str;
73                 }
74         }
75
76         while ((ptr > res) && isspace(*ptr))
77                 ptr--;
78
79         return sfh_hash(res, ptr - res);
80 }
81
82 static int lmo_L_hash(lua_State *L) {
83         uint32_t hash = _lmo_hash_string(L, 1);
84         lua_pushinteger(L, (lua_Integer)hash);
85         return 1;
86 }
87
88 static lmo_luaentry_t *_lmo_push_entry(lua_State *L) {
89         lmo_luaentry_t *le;
90
91         if( (le = lua_newuserdata(L, sizeof(lmo_luaentry_t))) != NULL )
92         {
93                 luaL_getmetatable(L, LMO_ENTRY_META);
94                 lua_setmetatable(L, -2);
95
96                 return le;
97         }
98
99         return NULL;
100 }
101
102 static int _lmo_lookup(lua_State *L, lmo_archive_t *ar, uint32_t hash) {
103         lmo_entry_t *e = ar->index;
104         lmo_luaentry_t *le = NULL;
105
106         while( e != NULL )
107         {
108                 if( e->key_id == hash )
109                 {
110                         if( (le = _lmo_push_entry(L)) != NULL )
111                         {
112                                 le->archive = ar;
113                                 le->entry   = e;
114                                 return 1;
115                         }
116                         else
117                         {
118                                 lua_pushnil(L);
119                                 lua_pushstring(L, "out of memory");
120                                 return 2;
121                         }
122                 }
123
124                 e = e->next;
125         }
126
127         lua_pushnil(L);
128         return 1;
129 }
130
131 static int lmo_L_get(lua_State *L) {
132         lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
133         uint32_t hash = (uint32_t) luaL_checkinteger(L, 2);
134         return _lmo_lookup(L, *ar, hash);
135 }
136
137 static int lmo_L_lookup(lua_State *L) {
138         lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
139         uint32_t hash = _lmo_hash_string(L, 2);
140         return _lmo_lookup(L, *ar, hash);
141 }
142
143 static int lmo_L_foreach(lua_State *L) {
144         lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
145         lmo_entry_t *e = (*ar)->index;
146
147         if( lua_isfunction(L, 2) )
148         {
149                 while( e != NULL )
150                 {
151                         lua_pushvalue(L, 2);
152                         lua_pushinteger(L, e->key_id);
153                         lua_pushlstring(L, &(*ar)->mmap[e->offset], e->length);
154                         lua_pcall(L, 2, 0, 0);
155                         e = e->next;
156                 }
157         }
158
159         return 0;
160 }
161
162 static int lmo_L__gc(lua_State *L) {
163         lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
164
165         if( (*ar) != NULL )
166                 lmo_close(*ar);
167
168         *ar = NULL;
169
170         return 0;
171 }
172
173 static int lmo_L__tostring(lua_State *L) {
174         lmo_archive_t **ar = luaL_checkudata(L, 1, LMO_ARCHIVE_META);
175         lua_pushfstring(L, "LMO Archive (%d bytes)", (*ar)->length);
176         return 1;
177 }
178
179
180 static int _lmo_convert_entry(lua_State *L, int idx) {
181         lmo_luaentry_t *le = luaL_checkudata(L, idx, LMO_ENTRY_META);
182
183         lua_pushlstring(L,
184                 &le->archive->mmap[le->entry->offset],
185                 le->entry->length
186         );
187
188         return 1;
189 }
190
191 static int lmo_L_entry__tostring(lua_State *L) {
192         return _lmo_convert_entry(L, 1);
193 }
194
195 static int lmo_L_entry__concat(lua_State *L) {
196         if( lua_isuserdata(L, 1) )
197                 _lmo_convert_entry(L, 1);
198         else
199                 lua_pushstring(L, lua_tostring(L, 1));
200
201         if( lua_isuserdata(L, 2) )
202                 _lmo_convert_entry(L, 2);
203         else
204                 lua_pushstring(L, lua_tostring(L, 2));
205
206         lua_concat(L, 2);
207
208         return 1;
209 }
210
211 static int lmo_L_entry__len(lua_State *L) {
212         lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
213         lua_pushinteger(L, le->entry->length);
214         return 1;
215 }
216
217 static int lmo_L_entry__gc(lua_State *L) {
218         lmo_luaentry_t *le = luaL_checkudata(L, 1, LMO_ENTRY_META);
219         le->archive = NULL;
220         le->entry   = NULL;
221         return 0;
222 }
223
224
225 /* lmo method table */
226 static const luaL_reg M[] = {
227         {"close",               lmo_L__gc},
228         {"get",                 lmo_L_get},
229         {"lookup",              lmo_L_lookup},
230         {"foreach",             lmo_L_foreach},
231         {"__tostring",  lmo_L__tostring},
232         {"__gc",                lmo_L__gc},
233         {NULL,                  NULL}
234 };
235
236 /* lmo.entry method table */
237 static const luaL_reg E[] = {
238         {"__tostring",  lmo_L_entry__tostring},
239         {"__concat",    lmo_L_entry__concat},
240         {"__len",               lmo_L_entry__len},
241         {"__gc",                lmo_L_entry__gc},
242         {NULL,                  NULL}
243 };
244
245 /* module table */
246 static const luaL_reg R[] = {
247         {"open",        lmo_L_open},
248         {"hash",        lmo_L_hash},
249         {NULL,          NULL}
250 };
251
252 LUALIB_API int luaopen_lmo(lua_State *L) {
253         luaL_newmetatable(L, LMO_ARCHIVE_META);
254         luaL_register(L, NULL, M);
255         lua_pushvalue(L, -1);
256         lua_setfield(L, -2, "__index");
257         lua_setglobal(L, LMO_ARCHIVE_META);
258
259         luaL_newmetatable(L, LMO_ENTRY_META);
260         luaL_register(L, NULL, E);
261         lua_pushvalue(L, -1);
262         lua_setfield(L, -2, "__index");
263         lua_setglobal(L, LMO_ENTRY_META);       
264
265         luaL_register(L, LMO_LUALIB_META, R);
266
267         return 1;
268 }