More C-Functions (luci.cutil.instanceof, luci.cutil.pcdata)
[project/luci.git] / libs / core / src / luci_cutil.c
1 /**
2  * LuCI Core - Utility library
3  * Copyright (C) 2008 Steven Barth <steven@midlink.org>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "lauxlib.h"
19
20 #define LUCI_MODNAME "luci.cutil"
21 #define LUCI_MODDESC "LuCI Core Utility Library"
22 #define LUCI_MODCOPY "2008 Steven Barth"
23
24
25 /* Pythonic overloaded MOD operator */
26 static int luci__string_mod(lua_State *L) {
27         int i, n=1;
28
29         luaL_checkstring(L, 1);
30         luaL_checkany(L, 2);
31
32         /* Discard further arguments */
33         lua_settop(L, 2);
34
35         /* Get format and push it to the bottom of the stack */
36         lua_getfield(L, 1, "format");
37         lua_insert(L, 1);
38
39         /* If second argument is a table, unpack it */
40         if (lua_istable(L, 3)) {
41                 n = lua_objlen(L, 3);
42                 if (n > 0) {
43                         luaL_checkstack(L, n, "too many results to unpack");
44                         for (i=1; i<=n; i++) {
45                                 lua_rawgeti(L, 3, i);
46                         }
47                 } else {
48                         n = 0;
49                 }
50                 lua_remove(L, 3);
51         }
52
53         lua_call(L, n+1, 1);
54         return 1;
55 }
56
57 /* Instantiate a class */
58 static int luci__instantiate(lua_State *L) {
59         luaL_checktype(L, 1, LUA_TTABLE);
60
61         /* Create the object */
62         lua_newtable(L);
63
64         /* Create the metatable */
65         lua_createtable(L, 0, 1);
66         lua_pushvalue(L, 1);
67         lua_setfield(L, -2, "__index");
68         lua_setmetatable(L, -2);
69
70         /* Move instance at the bottom of the stack */
71         lua_replace(L, 1);
72
73         /* Invoke constructor if it exists */
74         lua_getfield(L, 1, "__init__");
75         if (lua_isfunction(L, -1)) {
76                 /* Put instance at the bottom for the 2nd time */
77                 lua_pushvalue(L, 1);
78                 lua_insert(L, 1);
79
80                 /* Call constructor */
81                 lua_insert(L, 2);
82                 lua_call(L, lua_gettop(L)-2, 0);
83         }
84
85         lua_settop(L, 1);
86         return 1;
87 }
88
89
90 /* luci.cutil.class(baseclass) */
91 static int luci_class(lua_State *L) {
92         /* Create class */
93         lua_newtable(L);
94
95         /* Create metatable and register parent class if any */
96         if (lua_gettop(L) > 1 && lua_istable(L, 1)) {
97                 lua_createtable(L, 0, 2);
98                 lua_pushvalue(L, 1);
99                 lua_setfield(L, -2, "__index");
100         } else {
101                 lua_createtable(L, 0, 1);
102         }
103
104         /* Set instantiator */
105         lua_pushcfunction(L, luci__instantiate);
106         lua_setfield(L, -2, "__call");
107
108         lua_setmetatable(L, -2);
109         return 1;
110 }
111
112 /* luci.cutil.instanceof(object, class) */
113 static int luci_instanceof(lua_State *L) {
114         int stat = 0;
115
116         luaL_checkany(L, 1);
117         luaL_checkany(L, 2);
118
119         if (lua_getmetatable(L, 1)) {
120                 /* get parent class */
121                 lua_getfield(L, -1, "__index");
122                 while (lua_istable(L, -1)) {
123                         /* parent class == class */
124                         if (lua_equal(L, -1, 2)) {
125                                 stat = 1;
126                                 break;
127                         }
128
129                         /* remove last metatable */
130                         lua_remove(L, -2);
131
132                         /* get metatable of parent class */
133                         if (lua_getmetatable(L, -1)) {
134                                 /* remove last parent class */
135                                 lua_remove(L, -2);
136
137                                 /* get next parent class */
138                                 lua_getfield(L, -1, "__index");
139                         } else {
140                                 break;
141                         }
142                 }
143         }
144
145         lua_pushboolean(L, stat);
146         return 1;
147 }
148
149
150 /* luci.cutil.pcdata(obj) */
151 static int luci_pcdata(lua_State *L) {
152         if (lua_isnone(L, 1)) {
153                 lua_pushnil(L);
154                 return 1;
155         }
156
157         /* Discard anything else */
158         lua_settop(L, 1);
159
160         /* tostring(obj) */
161         lua_pushvalue(L, lua_upvalueindex(1));
162         lua_insert(L, 1);
163         lua_call(L, 1, 1);
164
165         /* pattern */
166         lua_pushvalue(L, lua_upvalueindex(2));
167
168         /* repl */
169         lua_pushvalue(L, lua_upvalueindex(3));
170
171         /* get gsub function */
172         lua_getfield(L, -3, "gsub");
173         lua_insert(L, 1);
174
175         /* tostring(obj):gsub(pattern, repl) */
176         lua_call(L, 3, 1);
177         return 1;
178 }
179
180
181 /* Registration helper for luci.cutil.pcdata */
182 static void luci__register_pcdata(lua_State *L) {
183         /* tostring */
184         lua_getfield(L, LUA_GLOBALSINDEX, "tostring");
185
186         /* pattern */
187         lua_pushliteral(L, "[&\"'<>]");
188
189         /* repl */
190         lua_createtable(L, 0, 5);
191
192         lua_pushliteral(L, "&#38;");
193         lua_setfield(L, -2, "&");
194         lua_pushliteral(L, "&#34;");
195         lua_setfield(L, -2, "\"");
196         lua_pushliteral(L, "&#39;");
197         lua_setfield(L, -2, "'");
198         lua_pushliteral(L, "&#60;");
199         lua_setfield(L, -2, "<");
200         lua_pushliteral(L, "&#62;");
201         lua_setfield(L, -2, ">");
202
203         /* register function */
204         lua_pushcclosure(L, luci_pcdata, 3);
205         lua_setfield(L, -2, "pcdata");
206 }
207
208 /* Registry */
209 static const luaL_Reg registry[] = {
210                 {"class",               luci_class},
211                 {"instanceof",  luci_instanceof},
212                 { NULL,                 NULL },
213 };
214
215 /* Registrator */
216 LUALIB_API int luaopen_luci_cutil(lua_State *L) {
217         luaL_register(L, LUCI_MODNAME, registry);
218
219         lua_pushliteral(L, LUCI_MODDESC);
220         lua_setfield(L, -2, "_DESCRIPTION");
221
222         lua_pushliteral(L, LUCI_MODCOPY);
223         lua_setfield(L, -2, "_COPYRIGHT");
224
225         /* Additional registrations */
226         luci__register_pcdata(L);
227
228
229         /* Register pythonic printf string operator */
230         lua_pushliteral(L, "");
231         lua_getmetatable(L, -1);
232         lua_pushcfunction(L, luci__string_mod);
233         lua_setfield(L, -2, "__mod");
234         lua_pop(L, 2);
235
236         return 1;
237 }