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 }