ff747f7013e4b40d777a4d3af2245a281209106d
[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 VALUE rrd_call(
84     RRDFUNC func,
85     VALUE args)
86 {
87     string_arr a;
88
89     a = string_arr_new(args);
90     reset_rrd_state();
91     func(a.len, a.strings);
92     string_arr_delete(a);
93
94     RRD_CHECK_ERROR return Qnil;
95 }
96
97 VALUE rb_rrd_create(
98     VALUE self,
99     VALUE args)
100 {
101     return rrd_call(rrd_create, args);
102 }
103
104 VALUE rb_rrd_dump(
105     VALUE self,
106     VALUE args)
107 {
108     return rrd_call(rrd_dump, args);
109 }
110
111 VALUE rb_rrd_fetch(
112     VALUE self,
113     VALUE args)
114 {
115     string_arr a;
116     unsigned long i, j, k, step, ds_cnt;
117     rrd_value_t *raw_data;
118     char    **raw_names;
119     VALUE     data, names, result;
120     time_t    start, end;
121
122     a = string_arr_new(args);
123     reset_rrd_state();
124     rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names,
125               &raw_data);
126     string_arr_delete(a);
127
128     RRD_CHECK_ERROR names = rb_ary_new();
129
130     for (i = 0; i < ds_cnt; i++) {
131         rb_ary_push(names, rb_str_new2(raw_names[i]));
132         free(raw_names[i]);
133     }
134     free(raw_names);
135
136     k = 0;
137     data = rb_ary_new();
138     for (i = start; i <= end; i += step) {
139         VALUE     line = rb_ary_new2(ds_cnt);
140
141         for (j = 0; j < ds_cnt; j++) {
142             rb_ary_store(line, j, rb_float_new(raw_data[k]));
143             k++;
144         }
145         rb_ary_push(data, line);
146     }
147     free(raw_data);
148
149     result = rb_ary_new2(5);
150     rb_ary_store(result, 0, INT2NUM(start));
151     rb_ary_store(result, 1, INT2NUM(end));
152     rb_ary_store(result, 2, names);
153     rb_ary_store(result, 3, data);
154     rb_ary_store(result, 4, INT2FIX(step));
155     return result;
156 }
157
158 VALUE rb_rrd_graph(
159     VALUE self,
160     VALUE args)
161 {
162     string_arr a;
163     char    **calcpr, **p;
164     VALUE     result, print_results;
165     int       xsize, ysize;
166     double    ymin, ymax;
167
168     a = string_arr_new(args);
169     reset_rrd_state();
170     rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
171     string_arr_delete(a);
172
173     RRD_CHECK_ERROR result = rb_ary_new2(3);
174
175     print_results = rb_ary_new();
176     p = calcpr;
177     for (p = calcpr; p && *p; p++) {
178         rb_ary_push(print_results, rb_str_new2(*p));
179         free(*p);
180     }
181     free(calcpr);
182     rb_ary_store(result, 0, print_results);
183     rb_ary_store(result, 1, INT2FIX(xsize));
184     rb_ary_store(result, 2, INT2FIX(ysize));
185     return result;
186 }
187
188 VALUE rb_rrd_info(
189     VALUE self,
190     VALUE args)
191 {
192     string_arr a;
193     info_t   *p, *data;
194     VALUE     result;
195
196     a = string_arr_new(args);
197     data = rrd_info(a.len, a.strings);
198     string_arr_delete(a);
199
200     RRD_CHECK_ERROR result = rb_hash_new();
201
202     while (data) {
203         VALUE     key = rb_str_new2(data->key);
204
205         switch (data->type) {
206         case RD_I_VAL:
207             if (isnan(data->value.u_val)) {
208                 rb_hash_aset(result, key, Qnil);
209             } else {
210                 rb_hash_aset(result, key, rb_float_new(data->value.u_val));
211             }
212             break;
213         case RD_I_CNT:
214             rb_hash_aset(result, key, INT2FIX(data->value.u_cnt));
215             break;
216         case RD_I_STR:
217             rb_hash_aset(result, key, rb_str_new2(data->value.u_str));
218             free(data->value.u_str);
219             break;
220         }
221         p = data;
222         data = data->next;
223         free(p);
224     }
225     return result;
226 }
227
228 VALUE rb_rrd_last(
229     VALUE self,
230     VALUE args)
231 {
232     string_arr a;
233     time_t    last;
234
235     a = string_arr_new(args);
236     reset_rrd_state();
237     last = rrd_last(a.len, a.strings);
238     string_arr_delete(a);
239
240     RRD_CHECK_ERROR
241         return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
242 }
243
244 VALUE rb_rrd_resize(
245     VALUE self,
246     VALUE args)
247 {
248     return rrd_call(rrd_resize, args);
249 }
250
251 VALUE rb_rrd_restore(
252     VALUE self,
253     VALUE args)
254 {
255     return rrd_call(rrd_restore, args);
256 }
257
258 VALUE rb_rrd_tune(
259     VALUE self,
260     VALUE args)
261 {
262     return rrd_call(rrd_tune, args);
263 }
264
265 VALUE rb_rrd_update(
266     VALUE self,
267     VALUE args)
268 {
269     return rrd_call(rrd_update, args);
270 }
271
272 void Init_RRD(
273     )
274 {
275     mRRD = rb_define_module("RRD");
276     rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
277
278     rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
279     rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
280     rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
281     rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
282     rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
283     rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
284     rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
285     rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
286     rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
287     rb_define_module_function(mRRD, "info", rb_rrd_info, -2);
288 }