I finally finished the first version of the patch (attached) -- Fidelis Assis fideli...
[rrdtool.git] / bindings / lua / rrdlua.c
1 /*
2  * Lua bindings for RRDTool
3  *
4  * This software is licensed to the public under the Free Software
5  * Foundation's GNU GPL, version 2 or later. You may obtain a copy
6  * of the GPL by visiting the Free Software Foundations web site at
7  * www.fsf.org, and a copy is included in this distribution.
8  *
9  * Copyright 2008 Fidelis Assis, all rights reserved.
10  *
11  */
12
13 #include <ctype.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <math.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <inttypes.h>
23
24 #include "lua.h"
25 #include "lauxlib.h"
26 #include "lualib.h"
27 #include "../../src/rrd_tool.h"
28
29 extern void rrd_freemem(void *mem);
30
31 extern int luaopen_rrd (lua_State * L);
32 typedef int (*RRD_FUNCTION)(int, char **);
33 typedef rrd_info_t *(RRD_FUNCTION_V)(int, char **);
34
35 /**********************************************************/
36
37 static void reset_rrd_state(void)
38 {
39     optind = 0;
40     opterr = 0;
41     rrd_clear_error();
42 }
43
44 static char **make_argv(const char *cmd, lua_State * L)
45 {
46   char **argv;
47   int i;
48   int argc = lua_gettop(L) + 1;
49
50   if (!(argv = calloc(argc, sizeof (char *)))) 
51     /* raise an error and never return */
52     luaL_error(L, "Can't allocate memory for arguments array", cmd);
53
54   /* fprintf(stderr, "Args:\n"); */
55   argv[0] = (char *) cmd; /* Dummy arg. Cast to (char *) because rrd */
56                           /* functions don't expect (const * char)   */
57   /* fprintf(stderr, "%s\n", argv[0]); */
58   for (i=1; i<argc; i++) {
59     /* accepts string or number */
60     if (lua_isstring(L, i) || lua_isnumber(L, i)) {
61       if (!(argv[i] = strdup(lua_tostring (L, i)))) {
62         /* raise an error and never return */
63         luaL_error(L, "%s - error duplicating string area for arg #%d",
64                    cmd, i);
65       }
66     } else {
67       /* raise an error and never return */
68       luaL_error(L, "Invalid arg #%d to %s: args must be strings or numbers",
69                  i, cmd);
70     }
71     /* fprintf(stderr, "%s\n", argv[i]); */
72   }
73   return argv;
74 }
75
76 static int
77 rrd_common_call (lua_State *L, const char *cmd, RRD_FUNCTION rrd_function)
78 {
79   char **argv;
80   int argc = lua_gettop(L) + 1;
81
82   argv = make_argv(cmd, L);
83   reset_rrd_state();
84   rrd_function(argc, argv);
85   free(argv);
86   if (rrd_test_error()) luaL_error(L, rrd_get_error());
87   return 0;
88 }
89
90 #if defined(DINF)
91 static int
92 lua_rrd_infocall(lua_State *L, const char *cmd, RRD_FUNCTION_V rrd_function)
93 {
94   char **argv;
95   rrd_info_t *p, *data;
96   int argc = lua_gettop(L) + 1;
97
98   argv = make_argv(cmd, L);
99   reset_rrd_state();
100   data = rrd_function(argc, argv);
101   free(argv);
102   if (rrd_test_error()) luaL_error(L, rrd_get_error());
103
104   lua_newtable(L);
105   p = data;
106   while (data) {
107     lua_pushstring(L, data->key);
108     switch (data->type) {
109       case RD_I_CNT:
110         if (isnan(data->value.u_val)) {
111           lua_pushnil(L); 
112         } else {
113           lua_pushnumber(L, (lua_Number) data->value.u_val);
114         }
115         lua_rawset(L, -3);
116         break;
117       case RD_I_VAL:
118         lua_pushnumber(L, (lua_Number) data->value.u_val);
119         lua_rawset(L, -3);
120         break;
121       case RD_I_STR:
122         lua_pushstring(L, data->value.u_str);
123         lua_rawset(L, -3);
124         break;
125       case RD_I_BLO:
126         lua_pushlstring(L, (const char *) data->value.u_blo.ptr,
127                         data->value.u_blo.size);
128         lua_rawset(L, -3);
129         break;
130       default:
131         rrd_info_free(p); 
132         return luaL_error(L, "Wrong data type to info call");
133         break;
134     }
135     data = data->next;
136   }
137   rrd_info_free(p); 
138   return 1;
139 }
140 #endif
141
142 /**********************************************************/
143
144 static int
145 lua_rrd_create (lua_State * L)
146 {
147   rrd_common_call(L, "create", rrd_create);
148   return 0;
149 }
150
151 static int
152 lua_rrd_dump (lua_State * L)
153 {
154   rrd_common_call(L, "dump", rrd_dump);
155   return 0;
156 }
157
158 static int
159 lua_rrd_resize (lua_State * L)
160 {
161   rrd_common_call(L, "resize", rrd_resize);
162   return 0;
163 }
164
165 static int
166 lua_rrd_restore (lua_State * L)
167 {
168   rrd_common_call(L, "restore", rrd_restore);
169   return 0;
170 }
171
172 static int
173 lua_rrd_tune (lua_State * L)
174 {
175   rrd_common_call(L, "tune", rrd_tune);
176   return 0;
177 }
178
179 static int
180 lua_rrd_update (lua_State * L)
181 {
182   rrd_common_call(L, "update", rrd_update);
183   return 0;
184 }
185
186 static int
187 lua_rrd_fetch (lua_State * L)
188 {
189   int argc = lua_gettop(L) + 1;
190   char **argv = make_argv("fetch", L);
191   unsigned long i, j, step, ds_cnt;
192   rrd_value_t *data, *p;
193   char    **names;
194   time_t  t, start, end;
195
196   reset_rrd_state();
197   rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &names, &data);
198   free(argv);
199   if (rrd_test_error()) luaL_error(L, rrd_get_error());
200
201   lua_pushnumber(L, (lua_Number) start);
202   lua_pushnumber(L, (lua_Number) step);
203   /* fprintf(stderr, "%lu, %lu, %lu, %lu\n", start, end, step, num_points); */
204
205   /* create the ds names array */
206   lua_newtable(L);
207   for (i=0; i<ds_cnt; i++) {
208     lua_pushstring(L, names[i]);
209     lua_rawseti(L, -2, i+1);
210     rrd_freemem(names[i]);
211   }
212   rrd_freemem(names);
213
214   /* create the data points array */
215   lua_newtable(L);
216   p = data;
217   for (t=start, i=0; t<end; t+=step, i++) {
218     lua_newtable(L);
219     for (j=0; j<ds_cnt; j++) {
220       /*fprintf(stderr, "Point #%lu\n", j+1); */
221       lua_pushnumber(L, (lua_Number) *p++);
222       lua_rawseti(L, -2, j+1);
223     }
224     lua_rawseti(L, -2, i+1);
225   }
226   rrd_freemem(data);
227
228   /* return the end as the last value */
229   lua_pushnumber(L, (lua_Number) end);
230
231   return 5;
232 }
233
234 static int
235 lua_rrd_first (lua_State * L)
236 {
237   time_t first;
238   int argc = lua_gettop(L) + 1;
239   char **argv = make_argv("first", L);
240   reset_rrd_state();
241   first = rrd_first(argc, argv);
242   free(argv);
243   if (rrd_test_error()) luaL_error(L, rrd_get_error());
244   lua_pushnumber(L, (lua_Number) first);
245   return 1;
246 }
247
248 static int
249 lua_rrd_last (lua_State * L)
250 {
251   time_t last;
252   int argc = lua_gettop(L) + 1;
253   char **argv = make_argv("last", L);
254   reset_rrd_state();
255   last = rrd_last(argc, argv);
256   free(argv);
257   if (rrd_test_error()) luaL_error(L, rrd_get_error());
258   lua_pushnumber(L, (lua_Number) last);
259   return 1;
260 }
261
262 static int
263 lua_rrd_graph (lua_State * L)
264 {
265   int argc = lua_gettop(L) + 1;
266   char **argv = make_argv("last", L);
267   char **calcpr;
268   int i, xsize, ysize;
269   double ymin, ymax;
270
271   reset_rrd_state();
272   rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
273   free(argv);
274   if (rrd_test_error()) luaL_error(L, rrd_get_error());
275   lua_pushnumber(L, (lua_Number) xsize);
276   lua_pushnumber(L, (lua_Number) ysize);
277   lua_newtable(L);
278   for (i = 0; calcpr && calcpr[i]; i++) {
279       lua_pushstring(L, calcpr[i]);
280       lua_rawseti(L, -2, i+1);
281       rrd_freemem(calcpr[i]);
282   }
283   rrd_freemem(calcpr);
284   return 3;
285 }
286
287 #if defined(DINF)
288 static int
289 lua_rrd_info (lua_State * L)
290 {
291   return lua_rrd_infocall(L, "info", rrd_info);
292 }
293
294 static int
295 lua_rrd_graphv (lua_State * L)
296 {
297   return lua_rrd_infocall(L, "graphv", rrd_graph_v);
298 }
299
300 static int
301 lua_rrd_updatev (lua_State * L)
302 {
303   return lua_rrd_infocall(L, "updatev", rrd_update_v);
304 }
305 #endif
306
307 /**********************************************************/
308
309 /*
310 ** Assumes the table is on top of the stack.
311 */
312 static void
313 set_info (lua_State * L)
314 {
315   lua_pushliteral (L, "_COPYRIGHT");
316   lua_pushliteral (L, "Copyright (C) 2008 Fidelis Assis");
317   lua_settable (L, -3);
318   lua_pushliteral (L, "_DESCRIPTION");
319   lua_pushliteral (L, "RRD-lua is a Lua binding for RRDTool.");
320   lua_settable (L, -3);
321   lua_pushliteral (L, "_NAME");
322   lua_pushliteral (L, "RRD-Lua");
323   lua_settable (L, -3);
324   lua_pushliteral (L, "_VERSION");
325   lua_pushliteral (L, LIB_VERSION);
326   lua_settable (L, -3);
327 }
328
329 /**********************************************************/
330
331 static const struct luaL_reg rrd[] = {
332   {"create", lua_rrd_create},
333   {"dump", lua_rrd_dump},
334   {"fetch", lua_rrd_fetch},
335   {"first", lua_rrd_first},
336   {"graph", lua_rrd_graph},
337   {"last", lua_rrd_last},
338   {"resize", lua_rrd_resize},
339   {"restore", lua_rrd_restore},
340   {"tune", lua_rrd_tune},
341   {"update", lua_rrd_update},
342 #if defined(DINF)
343   {"info", lua_rrd_info},
344   {"updatev", lua_rrd_updatev},
345   {"graphv", lua_rrd_graphv},
346 #endif
347   {NULL, NULL}
348 };
349
350
351 /*
352 ** Open RRD library
353 */
354 int
355 luaopen_rrd (lua_State * L)
356 {
357   luaL_register (L, "rrd", rrd);
358   set_info (L);
359   return 1;
360 }