it is rb_rrd_infocall not rrd_infocall ...
[rrdtool.git] / bindings / ruby / main.c
1 /* $Id$
2  * Substantial penalty for early withdrawal.
3  */
4
5 #include <unistd.h>
6 #include <ruby.h>
7 #include "../../src/rrd_tool.h"
8
9 typedef struct string_arr_t {
10     int       len;
11     char    **strings;
12 } string_arr;
13
14 VALUE     mRRD;
15 VALUE     rb_eRRDError;
16
17 typedef int (
18     *RRDFUNC) (
19     int argc,
20     char **argv);
21
22 #define RRD_CHECK_ERROR  \
23     if (rrd_test_error()) \
24       rb_raise(rb_eRRDError, rrd_get_error()); \
25     rrd_clear_error();
26
27 string_arr string_arr_new(
28     VALUE rb_strings)
29 {
30     string_arr a;
31     char      buf[64];
32     int       i;
33
34     Check_Type(rb_strings, T_ARRAY);
35     a.len = RARRAY(rb_strings)->len + 1;
36
37     a.strings = malloc(a.len * sizeof(char *));
38     a.strings[0] = "dummy"; /* first element is a dummy element */
39
40     for (i = 0; i < a.len - 1; i++) {
41         VALUE     v = rb_ary_entry(rb_strings, i);
42
43         switch (TYPE(v)) {
44         case T_STRING:
45             a.strings[i + 1] = strdup(STR2CSTR(v));
46             break;
47         case T_FIXNUM:
48             snprintf(buf, 63, "%d", FIX2INT(v));
49             a.strings[i + 1] = strdup(buf);
50             break;
51         default:
52             rb_raise(rb_eTypeError,
53                      "invalid argument - %s, expected T_STRING or T_FIXNUM on index %d",
54                      rb_class2name(CLASS_OF(v)), i);
55             break;
56         }
57     }
58
59     return a;
60 }
61
62 void string_arr_delete(
63     string_arr a)
64 {
65     int       i;
66
67     /* skip dummy first entry */
68     for (i = 1; i < a.len; i++) {
69         free(a.strings[i]);
70     }
71
72     free(a.strings);
73 }
74
75 void reset_rrd_state(
76     )
77 {
78     optind = 0;
79     opterr = 0;
80     rrd_clear_error();
81 }
82
83 /* Simple Calls */
84
85 VALUE rrd_call(
86     RRDFUNC func,
87     VALUE args)
88 {
89     string_arr a;
90
91     a = string_arr_new(args);
92     reset_rrd_state();
93     func(a.len, a.strings);
94     string_arr_delete(a);
95
96     RRD_CHECK_ERROR return Qnil;
97 }
98
99 VALUE rb_rrd_create(
100     VALUE self,
101     VALUE args)
102 {
103     return rrd_call(rrd_create, args);
104 }
105
106 VALUE rb_rrd_dump(
107     VALUE self,
108     VALUE args)
109 {
110     return rrd_call(rrd_dump, args);
111 }
112
113 VALUE rb_rrd_resize(
114     VALUE self,
115     VALUE args)
116 {
117     return rrd_call(rrd_resize, args);
118 }
119
120 VALUE rb_rrd_restore(
121     VALUE self,
122     VALUE args)
123 {
124     return rrd_call(rrd_restore, args);
125 }
126
127 VALUE rb_rrd_tune(
128     VALUE self,
129     VALUE args)
130 {
131     return rrd_call(rrd_tune, args);
132 }
133
134 VALUE rb_rrd_update(
135     VALUE self,
136     VALUE args)
137 {
138     return rrd_call(rrd_update, args);
139 }
140
141
142 /* Calls Returning Data via the Info Interface */
143
144 VALUE rb_rrd_infocall(
145     RRDFUNC func,
146     VALUE args)
147 {
148     string_arr a;
149     rrd_info_t *p, *data;
150     VALUE     result;
151
152     a = string_arr_new(args);
153     data = func(a.len, a.strings);
154     string_arr_delete(a);
155
156     RRD_CHECK_ERROR result = rb_hash_new();
157
158     while (data) {
159         VALUE     key = rb_str_new2(data->key);
160
161         switch (data->type) {
162         case RD_I_VAL:
163             if (isnan(data->value.u_val)) {
164                 rb_hash_aset(result, key, Qnil);
165             } else {
166                 rb_hash_aset(result, key, rb_float_new(data->value.u_val));
167             }
168             break;
169         case RD_I_CNT:
170             rb_hash_aset(result, key, INT2FIX(data->value.u_cnt));
171             break;
172         case RD_I_STR:
173             rb_hash_aset(result, key, rb_str_new2(data->value.u_str));
174             rrd_freemem(data->value.u_str);
175             break;
176         case RD_I_BLO:
177             rb_hash_aset(result, key,
178                          rb_str_new(data->value.u_blo.ptr,
179                                     data->value.u_blo.size));
180             rrd_freemem(data->value.u_blo.ptr);
181             break;
182         }
183         p = data;
184         data = data->next;
185         rrd_freemem(p);
186     }
187     return result;
188 }
189
190 VALUE rb_rrd_info(
191     VALUE self,
192     VALUE args)
193 {
194     return rb_rrd_infocall(rrd_info, args);
195 }
196
197 VALUE rb_rrd_updatev(
198     VALUE self,
199     VALUE args)
200 {
201     return rb_rrd_infocall(rrd_update_v, args);
202 }
203
204 VALUE rb_rrd_graphv(
205     VALUE self,
206     VALUE args)
207 {
208     return rb_rrd_infocall(rrd_graph_v, args);
209 }
210
211
212 /* Other Calls */
213
214 VALUE rb_rrd_fetch(
215     VALUE self,
216     VALUE args)
217 {
218     string_arr a;
219     unsigned long i, j, k, step, ds_cnt;
220     rrd_value_t *raw_data;
221     char    **raw_names;
222     VALUE     data, names, result;
223     time_t    start, end;
224
225     a = string_arr_new(args);
226     reset_rrd_state();
227     rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names,
228               &raw_data);
229     string_arr_delete(a);
230
231     RRD_CHECK_ERROR names = rb_ary_new();
232
233     for (i = 0; i < ds_cnt; i++) {
234         rb_ary_push(names, rb_str_new2(raw_names[i]));
235         rrd_freemem(raw_names[i]);
236     }
237     rrd_freemem(raw_names);
238
239     k = 0;
240     data = rb_ary_new();
241     for (i = start; i <= end; i += step) {
242         VALUE     line = rb_ary_new2(ds_cnt);
243
244         for (j = 0; j < ds_cnt; j++) {
245             rb_ary_store(line, j, rb_float_new(raw_data[k]));
246             k++;
247         }
248         rb_ary_push(data, line);
249     }
250     rrd_freemem(raw_data);
251
252     result = rb_ary_new2(5);
253     rb_ary_store(result, 0, INT2NUM(start));
254     rb_ary_store(result, 1, INT2NUM(end));
255     rb_ary_store(result, 2, names);
256     rb_ary_store(result, 3, data);
257     rb_ary_store(result, 4, INT2FIX(step));
258     return result;
259 }
260
261 VALUE rb_rrd_graph(
262     VALUE self,
263     VALUE args)
264 {
265     string_arr a;
266     char    **calcpr, **p;
267     VALUE     result, print_results;
268     int       xsize, ysize;
269     double    ymin, ymax;
270
271     a = string_arr_new(args);
272     reset_rrd_state();
273     rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
274     string_arr_delete(a);
275
276     RRD_CHECK_ERROR result = rb_ary_new2(3);
277
278     print_results = rb_ary_new();
279     p = calcpr;
280     for (p = calcpr; p && *p; p++) {
281         rb_ary_push(print_results, rb_str_new2(*p));
282         rrd_freemem(*p);
283     }
284     rrd_freemem(calcpr);
285     rb_ary_store(result, 0, print_results);
286     rb_ary_store(result, 1, INT2FIX(xsize));
287     rb_ary_store(result, 2, INT2FIX(ysize));
288     return result;
289 }
290
291
292 VALUE rb_rrd_last(
293     VALUE self,
294     VALUE args)
295 {
296     string_arr a;
297     time_t    last;
298
299     a = string_arr_new(args);
300     reset_rrd_state();
301     last = rrd_last(a.len, a.strings);
302     string_arr_delete(a);
303
304     RRD_CHECK_ERROR
305         return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
306 }
307
308 void Init_RRD(
309     )
310 {
311     mRRD = rb_define_module("RRD");
312     rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
313
314     rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
315     rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
316     rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
317     rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
318     rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
319     rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
320     rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
321     rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
322     rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
323     rb_define_module_function(mRRD, "info", rb_rrd_info, -2);
324     rb_define_module_function(mRRD, "updatev", rb_rrd_updatev, -2);
325     rb_define_module_function(mRRD, "graphv", rb_rrd_graphv, -2);
326 }