More luci.cutil
[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 luaL_checkstring(L, 1);
157
158 /* Discard anything else */
159 lua_settop(L, 1);
160
161 /* pattern */
162 lua_pushvalue(L, lua_upvalueindex(1));
163
164 /* repl */
165 lua_pushvalue(L, lua_upvalueindex(2));
166
167 /* get gsub function */
168 lua_getfield(L, 1, "gsub");
169 lua_insert(L, 1);
170
171 /* tostring(obj):gsub(pattern, repl) */
172 lua_call(L, 3, 1);
173 return 1;
174 }
175
176 /* luci.cutil.trim(str) */
177 static int luci_trim(lua_State *L) {
178 luaL_checkstring(L, 1);
179 lua_settop(L, 1);
180
181 /* pattern and repl */
182 lua_pushliteral(L, "^%s*(.-)%s*$");
183 lua_pushliteral(L, "%1");
184
185 /* get str.gsub */
186 lua_getfield(L, 1, "gsub");
187 lua_insert(L, 1);
188
189 /* str.gsub(str, pattern, repl) */
190 lua_call(L, 3, 1);
191 return 1;
192 }
193
194
195 /* Registration helper for luci.cutil.pcdata */
196 static void luci__register_pcdata(lua_State *L) {
197 /* pattern */
198 lua_pushliteral(L, "[&\"'<>]");
199
200 /* repl */
201 lua_createtable(L, 0, 5);
202
203 lua_pushliteral(L, "&#38;");
204 lua_setfield(L, -2, "&");
205 lua_pushliteral(L, "&#34;");
206 lua_setfield(L, -2, "\"");
207 lua_pushliteral(L, "&#39;");
208 lua_setfield(L, -2, "'");
209 lua_pushliteral(L, "&#60;");
210 lua_setfield(L, -2, "<");
211 lua_pushliteral(L, "&#62;");
212 lua_setfield(L, -2, ">");
213
214 /* register function */
215 lua_pushcclosure(L, luci_pcdata, 2);
216 lua_setfield(L, -2, "pcdata");
217 }
218
219 /* Registry */
220 static const luaL_Reg registry[] = {
221 {"class", luci_class},
222 {"instanceof", luci_instanceof},
223 {"trim", luci_trim},
224 { NULL, NULL },
225 };
226
227 /* Registrator */
228 LUALIB_API int luaopen_luci_cutil(lua_State *L) {
229 luaL_register(L, LUCI_MODNAME, registry);
230
231 lua_pushliteral(L, LUCI_MODDESC);
232 lua_setfield(L, -2, "_DESCRIPTION");
233
234 lua_pushliteral(L, LUCI_MODCOPY);
235 lua_setfield(L, -2, "_COPYRIGHT");
236
237 /* Additional registrations */
238 luci__register_pcdata(L);
239
240
241 /* Register pythonic printf string operator */
242 lua_pushliteral(L, "");
243 lua_getmetatable(L, -1);
244 lua_pushcfunction(L, luci__string_mod);
245 lua_setfield(L, -2, "__mod");
246 lua_pop(L, 2);
247
248 return 1;
249 }