c01e5949edc26fef5b54ba7674d45833e6b1f552
[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 #include "utils_lua.h"
24 #include "common.h"
25
26 static int ltoc_values (lua_State *l, /* {{{ */
27     const data_set_t *ds,
28     value_t *ret_values)
29 {
30   size_t i;
31   int status = 0;
32
33   if (!lua_istable (l, -1))
34     return (-1);
35
36   /* Push initial key */
37   lua_pushnil (l);
38   for (i = 0; i < ((size_t) ds->ds_num); i++)
39   {
40     /* Pops old key and pushed new key and value. */
41     status = lua_next (l, -2);
42     if (status == 0) /* no more elements */
43       break;
44
45     ret_values[i] = luaC_tovalue (l, /* idx = */ -1, ds->ds[i].type);
46
47     /* Pop the value */
48     lua_pop (l, /* nelems = */ 1);
49   }
50   /* Pop the key */
51   lua_pop (l, /* nelems = */ 1);
52
53   return (status);
54 } /* }}} int ltoc_values */
55
56 static int ltoc_table_values (lua_State *l, int idx, /* {{{ */
57     const data_set_t *ds, value_list_t *vl)
58 {
59   int status;
60
61   /* We're only called from "luaC_tovaluelist", which ensures that "idx" is an
62    * absolute index (i.e. a positive number) */
63   assert (idx > 0);
64
65   lua_pushstring (l, "values");
66   lua_gettable (l, idx);
67
68   if (!lua_istable (l, -1))
69   {
70     NOTICE ("lua plugin: ltoc_table_values: The \"values\" member is not a table.");
71     lua_pop (l, /* nelem = */ 1);
72     return (-1);
73   }
74
75   vl->values_len = ds->ds_num;
76   vl->values = calloc ((size_t) vl->values_len, sizeof (*vl->values));
77   if (vl->values == NULL)
78   {
79     ERROR ("lua plugin: calloc failed.");
80     vl->values_len = 0;
81     lua_pop (l, /* nelem = */ 1);
82     return (-1);
83   }
84
85   status = ltoc_values (l, ds, vl->values);
86
87   lua_pop (l, /* nelem = */ 1);
88
89   if (status != 0)
90   {
91     vl->values_len = 0;
92     sfree (vl->values);
93   }
94
95   return (status);
96 } /* }}} int ltoc_table_values */
97
98 /*
99  * Public functions
100  */
101 cdtime_t luaC_tocdtime (lua_State *l, int idx) /* {{{ */
102 {
103   double d;
104
105   if (!lua_isnumber (l, /* stack pos = */ idx))
106     return (0);
107
108   d = (double) lua_tonumber (l, idx);
109
110   return (DOUBLE_TO_CDTIME_T (d));
111 } /* }}} int ltoc_table_cdtime */
112
113 int luaC_tostringbuffer (lua_State *l, int idx, /* {{{ */
114     char *buffer, size_t buffer_size)
115 {
116   const char *str;
117
118   str = lua_tostring (l, idx);
119   if (str == NULL)
120     return (-1);
121
122   sstrncpy (buffer, str, buffer_size);
123   return (0);
124 } /* }}} int luaC_tostringbuffer */
125
126 value_t luaC_tovalue (lua_State *l, int idx, int ds_type) /* {{{ */
127 {
128   value_t v;
129
130   memset (&v, 0, sizeof (v));
131
132   if (!lua_isnumber (l, idx))
133     return (v);
134
135   if (ds_type == DS_TYPE_GAUGE)
136     v.gauge = (gauge_t) lua_tonumber (l, /* stack pos = */ -1);
137   else if (ds_type == DS_TYPE_DERIVE)
138     v.derive = (derive_t) lua_tointeger (l, /* stack pos = */ -1);
139   else if (ds_type == DS_TYPE_COUNTER)
140     v.counter = (counter_t) lua_tointeger (l, /* stack pos = */ -1);
141   else if (ds_type == DS_TYPE_ABSOLUTE)
142     v.absolute = (absolute_t) lua_tointeger (l, /* stack pos = */ -1);
143
144   return (v);
145 } /* }}} value_t luaC_tovalue */
146
147 value_list_t *luaC_tovaluelist (lua_State *l, int idx) /* {{{ */
148 {
149   const data_set_t *ds;
150   value_list_t *vl;
151   int status;
152 #if COLLECT_DEBUG
153   int stack_top_before = lua_gettop (l);
154 #endif
155
156   /* Convert relative indexes to absolute indexes, so it doesn't change when we
157    * push / pop stuff. */
158   if (idx < 1)
159     idx += lua_gettop (l) + 1;
160
161   /* Check that idx is in the valid range */
162   if ((idx < 1) || (idx > lua_gettop (l)))
163     return (NULL);
164
165   vl = malloc (sizeof (*vl));
166   if (vl == NULL)
167     return (NULL);
168   memset (vl, 0, sizeof (*vl));
169   vl->values = NULL;
170   vl->meta = NULL;
171
172   /* Push initial key */
173   lua_pushnil (l);
174   while (lua_next (l, idx) != 0)
175   {
176     const char *key = lua_tostring (l, /* stack pos = */ -2);
177
178     if (key == NULL)
179     {
180       DEBUG ("luaC_tovaluelist: Ignoring non-string key.");
181     }
182     else if (strcasecmp ("host", key) == 0)
183       luaC_tostringbuffer (l, /* idx = */ -1,
184           vl->host, sizeof (vl->host));
185     else if (strcasecmp ("plugin", key) == 0)
186       luaC_tostringbuffer (l, /* idx = */ -1,
187           vl->plugin, sizeof (vl->plugin));
188     else if (strcasecmp ("plugin_instance", key) == 0)
189       luaC_tostringbuffer (l, /* idx = */ -1,
190           vl->plugin_instance, sizeof (vl->plugin_instance));
191     else if (strcasecmp ("type", key) == 0)
192       luaC_tostringbuffer (l, /* idx = */ -1,
193           vl->type, sizeof (vl->type));
194     else if (strcasecmp ("type_instance", key) == 0)
195       luaC_tostringbuffer (l, /* idx = */ -1,
196           vl->type_instance, sizeof (vl->type_instance));
197     else if (strcasecmp ("time", key) == 0)
198       vl->time = luaC_tocdtime (l, -1);
199     else if (strcasecmp ("interval", key) == 0)
200       vl->interval = luaC_tocdtime (l, -1);
201     else if (strcasecmp ("values", key) == 0)
202     {
203       /* This key is not handled here, because we have to assure "type" is read
204        * first. */
205     }
206     else
207     {
208       DEBUG ("luaC_tovaluelist: Ignoring unknown key \"%s\".", key);
209     }
210
211     /* Pop the value */
212     lua_pop (l, 1);
213   }
214   /* Pop the key */
215   lua_pop (l, 1);
216
217   ds = plugin_get_ds (vl->type);
218   if (ds == NULL)
219   {
220     INFO ("lua plugin: Unable to lookup type \"%s\".", vl->type);
221     sfree (vl);
222     return (NULL);
223   }
224
225   status = ltoc_table_values (l, idx, ds, vl);
226   if (status != 0)
227   {
228     WARNING ("lua plugin: ltoc_table_values failed.");
229     sfree (vl);
230     return (NULL);
231   }
232
233 #if COLLECT_DEBUG
234   assert (stack_top_before == lua_gettop (l));
235 #endif
236   return (vl);
237 } /* }}} value_list_t *luaC_tovaluelist */
238
239 /* vim: set sw=2 sts=2 et fdm=marker : */