2 * collectd - src/utils_lua.c
3 * Copyright (C) 2010 Florian Forster
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * Florian Forster <octo at collectd.org>
27 /* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
28 * GCC will complain about the macro definition. */
29 #define DONT_POISON_SPRINTF_YET
31 #include "utils_lua.h"
34 static int ltoc_values(lua_State *L, /* {{{ */
35 const data_set_t *ds, value_t *ret_values) {
36 if (!lua_istable(L, -1)) {
37 WARNING("ltoc_values: not a table");
41 /* Push initial key */
42 lua_pushnil(L); /* +1 = 1 */
44 while (lua_next(L, -2) != 0) /* -1+2 = 2 || -1 = 0 */
46 if (i >= ds->ds_num) {
47 lua_pop(L, 2); /* -2 = 0 */
52 ret_values[i] = luaC_tovalue(L, -1, ds->ds[i].type);
55 lua_pop(L, 1); /* -1 = 1 */
57 } /* while (lua_next) */
59 if (i != ds->ds_num) {
60 WARNING("ltoc_values: invalid size for datasource \"%s\": expected %zu, "
62 ds->type, ds->ds_num, i);
67 } /* }}} int ltoc_values */
69 static int ltoc_table_values(lua_State *L, int idx, /* {{{ */
70 const data_set_t *ds, value_list_t *vl) {
71 /* We're only called from "luaC_tovaluelist", which ensures that "idx" is an
72 * absolute index (i.e. a positive number) */
75 lua_getfield(L, idx, "values");
76 if (!lua_istable(L, -1)) {
77 WARNING("utils_lua: ltoc_table_values: The \"values\" member is a %s "
78 "value, not a table.",
79 lua_typename(L, lua_type(L, -1)));
84 vl->values_len = ds->ds_num;
85 vl->values = calloc(vl->values_len, sizeof(*vl->values));
86 if (vl->values == NULL) {
87 ERROR("utils_lua: calloc failed.");
93 int status = ltoc_values(L, ds, vl->values);
103 } /* }}} int ltoc_table_values */
105 static int luaC_pushvalues(lua_State *L, const data_set_t *ds,
106 const value_list_t *vl) /* {{{ */
108 assert(vl->values_len == ds->ds_num);
111 for (size_t i = 0; i < vl->values_len; i++) {
112 lua_pushinteger(L, (lua_Integer)i + 1);
113 luaC_pushvalue(L, vl->values[i], ds->ds[i].type);
118 } /* }}} int luaC_pushvalues */
120 static int luaC_pushdstypes(lua_State *L, const data_set_t *ds) /* {{{ */
123 for (size_t i = 0; i < ds->ds_num; i++) {
124 lua_pushinteger(L, (lua_Integer)i);
125 lua_pushstring(L, DS_TYPE_TO_STRING(ds->ds[i].type));
130 } /* }}} int luaC_pushdstypes */
132 static int luaC_pushdsnames(lua_State *L, const data_set_t *ds) /* {{{ */
135 for (size_t i = 0; i < ds->ds_num; i++) {
136 lua_pushinteger(L, (lua_Integer)i);
137 lua_pushstring(L, ds->ds[i].name);
142 } /* }}} int luaC_pushdsnames */
147 cdtime_t luaC_tocdtime(lua_State *L, int idx) /* {{{ */
149 if (!lua_isnumber(L, /* stack pos = */ idx))
152 double d = lua_tonumber(L, idx);
154 return (DOUBLE_TO_CDTIME_T(d));
155 } /* }}} int ltoc_table_cdtime */
157 int luaC_tostringbuffer(lua_State *L, int idx, /* {{{ */
158 char *buffer, size_t buffer_size) {
159 const char *str = lua_tostring(L, idx);
163 sstrncpy(buffer, str, buffer_size);
165 } /* }}} int luaC_tostringbuffer */
167 value_t luaC_tovalue(lua_State *L, int idx, int ds_type) /* {{{ */
171 if (!lua_isnumber(L, idx))
174 if (ds_type == DS_TYPE_GAUGE)
175 v.gauge = (gauge_t)lua_tonumber(L, /* stack pos = */ -1);
176 else if (ds_type == DS_TYPE_DERIVE)
177 v.derive = (derive_t)lua_tointeger(L, /* stack pos = */ -1);
178 else if (ds_type == DS_TYPE_COUNTER)
179 v.counter = (counter_t)lua_tointeger(L, /* stack pos = */ -1);
180 else if (ds_type == DS_TYPE_ABSOLUTE)
181 v.absolute = (absolute_t)lua_tointeger(L, /* stack pos = */ -1);
184 } /* }}} value_t luaC_tovalue */
186 value_list_t *luaC_tovaluelist(lua_State *L, int idx) /* {{{ */
189 int stack_top_before = lua_gettop(L);
192 /* Convert relative indexes to absolute indexes, so it doesn't change when we
193 * push / pop stuff. */
195 idx += lua_gettop(L) + 1;
197 /* Check that idx is in the valid range */
198 if ((idx < 1) || (idx > lua_gettop(L))) {
199 DEBUG("luaC_tovaluelist: idx(%d), top(%d)", idx, stack_top_before);
203 value_list_t *vl = calloc(1, sizeof(*vl));
205 DEBUG("luaC_tovaluelist: calloc failed");
209 /* Push initial key */
211 while (lua_next(L, idx) != 0) {
212 const char *key = lua_tostring(L, -2);
215 DEBUG("luaC_tovaluelist: Ignoring non-string key.");
216 } else if (strcasecmp("host", key) == 0)
217 luaC_tostringbuffer(L, -1, vl->host, sizeof(vl->host));
218 else if (strcasecmp("plugin", key) == 0)
219 luaC_tostringbuffer(L, -1, vl->plugin, sizeof(vl->plugin));
220 else if (strcasecmp("plugin_instance", key) == 0)
221 luaC_tostringbuffer(L, -1, vl->plugin_instance,
222 sizeof(vl->plugin_instance));
223 else if (strcasecmp("type", key) == 0)
224 luaC_tostringbuffer(L, -1, vl->type, sizeof(vl->type));
225 else if (strcasecmp("type_instance", key) == 0)
226 luaC_tostringbuffer(L, -1, vl->type_instance,
227 sizeof(vl->type_instance));
228 else if (strcasecmp("time", key) == 0)
229 vl->time = luaC_tocdtime(L, -1);
230 else if (strcasecmp("interval", key) == 0)
231 vl->interval = luaC_tocdtime(L, -1);
232 else if (strcasecmp("values", key) == 0) {
233 /* This key is not handled here, because we have to assure "type" is read
236 DEBUG("luaC_tovaluelist: Ignoring unknown key \"%s\".", key);
243 const data_set_t *ds = plugin_get_ds(vl->type);
245 INFO("utils_lua: Unable to lookup type \"%s\".", vl->type);
250 int status = ltoc_table_values(L, idx, ds, vl);
252 WARNING("utils_lua: ltoc_table_values failed.");
258 assert(stack_top_before == lua_gettop(L));
261 } /* }}} value_list_t *luaC_tovaluelist */
263 int luaC_pushcdtime(lua_State *L, cdtime_t t) /* {{{ */
265 double d = CDTIME_T_TO_DOUBLE(t);
267 lua_pushnumber(L, (lua_Number)d);
269 } /* }}} int luaC_pushcdtime */
271 int luaC_pushvalue(lua_State *L, value_t v, int ds_type) /* {{{ */
273 if (ds_type == DS_TYPE_GAUGE)
274 lua_pushnumber(L, (lua_Number)v.gauge);
275 else if (ds_type == DS_TYPE_DERIVE)
276 lua_pushinteger(L, (lua_Integer)v.derive);
277 else if (ds_type == DS_TYPE_COUNTER)
278 lua_pushinteger(L, (lua_Integer)v.counter);
279 else if (ds_type == DS_TYPE_ABSOLUTE)
280 lua_pushinteger(L, (lua_Integer)v.absolute);
284 } /* }}} int luaC_pushvalue */
286 int luaC_pushvaluelist(lua_State *L, const data_set_t *ds,
287 const value_list_t *vl) /* {{{ */
291 lua_pushstring(L, vl->host);
292 lua_setfield(L, -2, "host");
294 lua_pushstring(L, vl->plugin);
295 lua_setfield(L, -2, "plugin");
296 lua_pushstring(L, vl->plugin_instance);
297 lua_setfield(L, -2, "plugin_instance");
299 lua_pushstring(L, vl->type);
300 lua_setfield(L, -2, "type");
301 lua_pushstring(L, vl->type_instance);
302 lua_setfield(L, -2, "type_instance");
304 luaC_pushvalues(L, ds, vl);
305 lua_setfield(L, -2, "values");
307 luaC_pushdstypes(L, ds);
308 lua_setfield(L, -2, "dstypes");
310 luaC_pushdsnames(L, ds);
311 lua_setfield(L, -2, "dsnames");
313 luaC_pushcdtime(L, vl->time);
314 lua_setfield(L, -2, "time");
316 luaC_pushcdtime(L, vl->interval);
317 lua_setfield(L, -2, "interval");
320 } /* }}} int luaC_pushvaluelist */
322 /* vim: set sw=2 sts=2 et fdm=marker : */