8992423dc2a30c294a3c237b6ce666824fcc8bc6
[collectd.git] / src / utils_lua.c
1 /**
2  * collectd - src/utils_lua.c
3  * Copyright (C) 2010       Florian Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; only version 2.1 of the License is
8  * applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors:
20  *   Florian Forster <octo at collectd.org>
21  **/
22
23 /* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
24  * GCC will complain about the macro definition. */
25 #define DONT_POISON_SPRINTF_YET
26
27 #include "utils_lua.h"
28 #include "common.h"
29
30 static int ltoc_values (lua_State *l, /* {{{ */
31     const data_set_t *ds,
32     value_t *ret_values)
33 {
34   size_t i;
35
36   if (!lua_istable (l, -1))
37     return (-1);
38
39   /* Push initial key */
40   lua_pushnil (l); /* +1 = 1 */
41   i = 0;
42   while (lua_next (l, /* idx = */ -2) != 0) /* -1+2 = 2 || -1 = 0 */
43   {
44     if (i >= ((size_t) ds->ds_num))
45     {
46       lua_pop (l, /* nelems = */ 2); /* -2 = 0 */
47       i++;
48       break;
49     }
50
51     ret_values[i] = luaC_tovalue (l, /* idx = */ -1, ds->ds[i].type);
52
53     /* Pop the value */
54     lua_pop (l, /* nelems = */ 1); /* -1 = 1 */
55     i++;
56   } /* while (lua_next) */
57
58   if (i == ((size_t) ds->ds_num))
59     return (0);
60   else
61     return (-1);
62 } /* }}} int ltoc_values */
63
64 static int ltoc_table_values (lua_State *l, int idx, /* {{{ */
65     const data_set_t *ds, value_list_t *vl)
66 {
67   int status;
68
69   /* We're only called from "luaC_tovaluelist", which ensures that "idx" is an
70    * absolute index (i.e. a positive number) */
71   assert (idx > 0);
72
73   lua_getfield (l, idx, "values");
74   if (!lua_istable (l, -1))
75   {
76     WARNING ("utils_lua: ltoc_table_values: The \"values\" member is a %s value, not a table.",
77         lua_typename (l, lua_type (l, -1)));
78     lua_pop (l, /* nelem = */ 1);
79     return (-1);
80   }
81
82   vl->values_len = ds->ds_num;
83   vl->values = calloc ((size_t) vl->values_len, sizeof (*vl->values));
84   if (vl->values == NULL)
85   {
86     ERROR ("utils_lua: calloc failed.");
87     vl->values_len = 0;
88     lua_pop (l, /* nelem = */ 1);
89     return (-1);
90   }
91
92   status = ltoc_values (l, ds, vl->values);
93
94   lua_pop (l, /* nelem = */ 1);
95
96   if (status != 0)
97   {
98     vl->values_len = 0;
99     sfree (vl->values);
100   }
101
102   return (status);
103 } /* }}} int ltoc_table_values */
104
105 static int luaC_pushvalues (lua_State *l, const data_set_t *ds, const value_list_t *vl) /* {{{ */
106 {
107   int i;
108
109   assert (vl->values_len == ds->ds_num);
110
111   lua_newtable (l);
112   for (i = 0; i < vl->values_len; i++)
113   {
114     lua_pushinteger (l, (lua_Integer) i);
115     luaC_pushvalue (l, vl->values[i], ds->ds[i].type);
116     lua_settable (l, /* idx = */ -3);
117   }
118
119   return (0);
120 } /* }}} int luaC_pushvalues */
121
122 static int luaC_pushdstypes (lua_State *l, const data_set_t *ds) /* {{{ */
123 {
124   int i;
125
126   lua_newtable (l);
127   for (i = 0; i < ds->ds_num; i++)
128   {
129     lua_pushinteger (l, (lua_Integer) i);
130     lua_pushstring (l, DS_TYPE_TO_STRING (ds->ds[i].type));
131     lua_settable (l, /* idx = */ -3);
132   }
133
134   return (0);
135 } /* }}} int luaC_pushdstypes */
136
137 static int luaC_pushdsnames (lua_State *l, const data_set_t *ds) /* {{{ */
138 {
139   int i;
140
141   lua_newtable (l);
142   for (i = 0; i < ds->ds_num; i++)
143   {
144     lua_pushinteger (l, (lua_Integer) i);
145     lua_pushstring (l, ds->ds[i].name);
146     lua_settable (l, /* idx = */ -3);
147   }
148
149   return (0);
150 } /* }}} int luaC_pushdsnames */
151
152 /*
153  * Public functions
154  */
155 cdtime_t luaC_tocdtime (lua_State *l, int idx) /* {{{ */
156 {
157   double d;
158
159   if (!lua_isnumber (l, /* stack pos = */ idx))
160     return (0);
161
162   d = (double) lua_tonumber (l, idx);
163
164   return (DOUBLE_TO_CDTIME_T (d));
165 } /* }}} int ltoc_table_cdtime */
166
167 int luaC_tostringbuffer (lua_State *l, int idx, /* {{{ */
168     char *buffer, size_t buffer_size)
169 {
170   const char *str;
171
172   str = lua_tostring (l, idx);
173   if (str == NULL)
174     return (-1);
175
176   sstrncpy (buffer, str, buffer_size);
177   return (0);
178 } /* }}} int luaC_tostringbuffer */
179
180 value_t luaC_tovalue (lua_State *l, int idx, int ds_type) /* {{{ */
181 {
182   value_t v;
183
184   memset (&v, 0, sizeof (v));
185
186   if (!lua_isnumber (l, idx))
187     return (v);
188
189   if (ds_type == DS_TYPE_GAUGE)
190     v.gauge = (gauge_t) lua_tonumber (l, /* stack pos = */ -1);
191   else if (ds_type == DS_TYPE_DERIVE)
192     v.derive = (derive_t) lua_tointeger (l, /* stack pos = */ -1);
193   else if (ds_type == DS_TYPE_COUNTER)
194     v.counter = (counter_t) lua_tointeger (l, /* stack pos = */ -1);
195   else if (ds_type == DS_TYPE_ABSOLUTE)
196     v.absolute = (absolute_t) lua_tointeger (l, /* stack pos = */ -1);
197
198   return (v);
199 } /* }}} value_t luaC_tovalue */
200
201 value_list_t *luaC_tovaluelist (lua_State *l, int idx) /* {{{ */
202 {
203   const data_set_t *ds;
204   value_list_t *vl;
205   int status;
206 #if COLLECT_DEBUG
207   int stack_top_before = lua_gettop (l);
208 #endif
209
210   /* Convert relative indexes to absolute indexes, so it doesn't change when we
211    * push / pop stuff. */
212   if (idx < 1)
213     idx += lua_gettop (l) + 1;
214
215   /* Check that idx is in the valid range */
216   if ((idx < 1) || (idx > lua_gettop (l)))
217     return (NULL);
218
219   vl = malloc (sizeof (*vl));
220   if (vl == NULL)
221     return (NULL);
222   memset (vl, 0, sizeof (*vl));
223   vl->values = NULL;
224   vl->meta = NULL;
225
226   /* Push initial key */
227   lua_pushnil (l);
228   while (lua_next (l, idx) != 0)
229   {
230     const char *key = lua_tostring (l, /* stack pos = */ -2);
231
232     if (key == NULL)
233     {
234       DEBUG ("luaC_tovaluelist: Ignoring non-string key.");
235     }
236     else if (strcasecmp ("host", key) == 0)
237       luaC_tostringbuffer (l, /* idx = */ -1,
238           vl->host, sizeof (vl->host));
239     else if (strcasecmp ("plugin", key) == 0)
240       luaC_tostringbuffer (l, /* idx = */ -1,
241           vl->plugin, sizeof (vl->plugin));
242     else if (strcasecmp ("plugin_instance", key) == 0)
243       luaC_tostringbuffer (l, /* idx = */ -1,
244           vl->plugin_instance, sizeof (vl->plugin_instance));
245     else if (strcasecmp ("type", key) == 0)
246       luaC_tostringbuffer (l, /* idx = */ -1,
247           vl->type, sizeof (vl->type));
248     else if (strcasecmp ("type_instance", key) == 0)
249       luaC_tostringbuffer (l, /* idx = */ -1,
250           vl->type_instance, sizeof (vl->type_instance));
251     else if (strcasecmp ("time", key) == 0)
252       vl->time = luaC_tocdtime (l, -1);
253     else if (strcasecmp ("interval", key) == 0)
254       vl->interval = luaC_tocdtime (l, -1);
255     else if (strcasecmp ("values", key) == 0)
256     {
257       /* This key is not handled here, because we have to assure "type" is read
258        * first. */
259     }
260     else
261     {
262       DEBUG ("luaC_tovaluelist: Ignoring unknown key \"%s\".", key);
263     }
264
265     /* Pop the value */
266     lua_pop (l, 1);
267   }
268
269   ds = plugin_get_ds (vl->type);
270   if (ds == NULL)
271   {
272     INFO ("utils_lua: Unable to lookup type \"%s\".", vl->type);
273     sfree (vl);
274     return (NULL);
275   }
276
277   status = ltoc_table_values (l, idx, ds, vl);
278   if (status != 0)
279   {
280     WARNING ("utils_lua: ltoc_table_values failed.");
281     sfree (vl);
282     return (NULL);
283   }
284
285 #if COLLECT_DEBUG
286   assert (stack_top_before == lua_gettop (l));
287 #endif
288   return (vl);
289 } /* }}} value_list_t *luaC_tovaluelist */
290
291 int luaC_pushcdtime (lua_State *l, cdtime_t t) /* {{{ */
292 {
293   double d = CDTIME_T_TO_DOUBLE (t);
294
295   lua_pushnumber (l, (lua_Number) d);
296   return (0);
297 } /* }}} int luaC_pushcdtime */
298
299 int luaC_pushvalue (lua_State *l, value_t v, int ds_type) /* {{{ */
300 {
301   if (ds_type == DS_TYPE_GAUGE)
302     lua_pushnumber (l, (lua_Number) v.gauge);
303   else if (ds_type == DS_TYPE_DERIVE)
304     lua_pushinteger (l, (lua_Integer) v.derive);
305   else if (ds_type == DS_TYPE_COUNTER)
306     lua_pushinteger (l, (lua_Integer) v.counter);
307   else if (ds_type == DS_TYPE_ABSOLUTE)
308     lua_pushinteger (l, (lua_Integer) v.absolute);
309   else
310     return (-1);
311   return (0);
312 } /* }}} int luaC_pushvalue */
313
314 int luaC_pushvaluelist (lua_State *l, const data_set_t *ds, const value_list_t *vl) /* {{{ */
315 {
316   lua_newtable (l);
317
318   lua_pushstring (l, vl->host);
319   lua_setfield (l, /* idx = */ -2, "host");
320
321   lua_pushstring (l, vl->plugin);
322   lua_setfield (l, /* idx = */ -2, "plugin");
323   lua_pushstring (l, vl->plugin_instance);
324   lua_setfield (l, /* idx = */ -2, "plugin_instance");
325
326   lua_pushstring (l, vl->type);
327   lua_setfield (l, /* idx = */ -2, "type");
328   lua_pushstring (l, vl->type_instance);
329   lua_setfield (l, /* idx = */ -2, "type_instance");
330
331   luaC_pushvalues (l, ds, vl);
332   lua_setfield (l, /* idx = */ -2, "values");
333
334   luaC_pushdstypes (l, ds);
335   lua_setfield (l, /* idx = */ -2, "dstypes");
336
337   luaC_pushdsnames (l, ds);
338   lua_setfield (l, /* idx = */ -2, "dsnames");
339
340   luaC_pushcdtime (l, vl->time);
341   lua_setfield (l, /* idx = */ -2, "time");
342
343   luaC_pushcdtime (l, vl->interval);
344   lua_setfield (l, /* idx = */ -2, "interval");
345
346   return (0);
347 } /* }}} int luaC_pushvaluelist */
348
349 /* vim: set sw=2 sts=2 et fdm=marker : */