new trunk based on current 1.2
[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 <rrd.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 (*RRDFUNC)(int argc, char ** argv);
18 #define RRD_CHECK_ERROR  \
19     if (rrd_test_error()) \
20       rb_raise(rb_eRRDError, rrd_get_error()); \
21     rrd_clear_error();
22
23 string_arr string_arr_new(VALUE rb_strings)
24 {
25     string_arr a;
26     char buf[64];
27     int i;
28    
29     Check_Type(rb_strings, T_ARRAY);
30     a.len = RARRAY(rb_strings)->len + 1;
31
32     a.strings = malloc(a.len * sizeof(char *));
33     a.strings[0] = "dummy";     /* first element is a dummy element */
34
35     for (i = 0; i < a.len - 1; i++) {
36         VALUE v = rb_ary_entry(rb_strings, i);
37         switch (TYPE(v)) {
38         case T_STRING:
39             a.strings[i + 1] = strdup(STR2CSTR(v));
40             break;
41         case T_FIXNUM:
42             snprintf(buf, 63, "%d", FIX2INT(v));
43             a.strings[i + 1] = strdup(buf);
44             break;
45         default:
46             rb_raise(rb_eTypeError, "invalid argument");
47             break;
48         }
49     }
50
51     return a;
52 }
53
54 void string_arr_delete(string_arr a)
55 {
56     int i;
57
58     /* skip dummy first entry */
59     for (i = 1; i < a.len; i++) {
60         free(a.strings[i]);
61     }
62
63     free(a.strings);
64 }
65
66 void reset_rrd_state()
67 {
68     optind = 0; 
69     opterr = 0;
70     rrd_clear_error();
71 }
72
73 VALUE rrd_call(RRDFUNC func, VALUE args)
74 {
75     string_arr a;
76
77     a = string_arr_new(args);
78     reset_rrd_state();
79     func(a.len, a.strings);
80     string_arr_delete(a);
81
82     RRD_CHECK_ERROR
83
84     return Qnil;
85 }
86
87 VALUE rb_rrd_create(VALUE self, VALUE args)
88 {
89     return rrd_call(rrd_create, args);
90 }
91
92 VALUE rb_rrd_dump(VALUE self, VALUE args)
93 {
94     return rrd_call(rrd_dump, args);
95 }
96
97 VALUE rb_rrd_fetch(VALUE self, VALUE args)
98 {
99     string_arr a;
100     unsigned long i, j, k, step, ds_cnt;
101     rrd_value_t *raw_data;
102     char **raw_names;
103     VALUE data, names, result;
104     time_t start, end;
105
106     a = string_arr_new(args);
107     reset_rrd_state();
108     rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names, &raw_data);
109     string_arr_delete(a);
110
111     RRD_CHECK_ERROR
112
113     names = rb_ary_new();
114     for (i = 0; i < ds_cnt; i++) {
115         rb_ary_push(names, rb_str_new2(raw_names[i]));
116         free(raw_names[i]);
117     }
118     free(raw_names);
119
120     k = 0;
121     data = rb_ary_new();
122     for (i = start; i <= end; i += step) {
123         VALUE line = rb_ary_new2(ds_cnt);
124         for (j = 0; j < ds_cnt; j++) {
125             rb_ary_store(line, j, rb_float_new(raw_data[k]));
126             k++;
127         }
128         rb_ary_push(data, line);
129     }
130     free(raw_data);
131    
132     result = rb_ary_new2(4);
133     rb_ary_store(result, 0, INT2FIX(start));
134     rb_ary_store(result, 1, INT2FIX(end));
135     rb_ary_store(result, 2, names);
136     rb_ary_store(result, 2, data);
137     return result;
138 }
139
140 VALUE rb_rrd_graph(VALUE self, VALUE args)
141 {
142     string_arr a;
143     char **calcpr, **p;
144     VALUE result, print_results;
145     int xsize, ysize;
146     double ymin, ymax;
147
148     a = string_arr_new(args);
149     reset_rrd_state();
150     rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
151     string_arr_delete(a);
152
153     RRD_CHECK_ERROR
154
155     result = rb_ary_new2(3);
156     print_results = rb_ary_new();
157     p = calcpr;
158     for (p = calcpr; p && *p; p++) {
159         rb_ary_push(print_results, rb_str_new2(*p));
160         free(*p);
161     }
162     free(calcpr);
163     rb_ary_store(result, 0, print_results);
164     rb_ary_store(result, 1, INT2FIX(xsize));
165     rb_ary_store(result, 2, INT2FIX(ysize));
166     return result;
167 }
168
169 /*
170 VALUE rb_rrd_info(VALUE self, VALUE args)
171 {
172     string_arr a;
173     info_t *p;
174     VALUE result;
175
176     a = string_arr_new(args);
177     data = rrd_info(a.len, a.strings);
178     string_arr_delete(a);
179
180     RRD_CHECK_ERROR
181
182     result = rb_hash_new();
183     while (data) {
184         VALUE key = rb_str_new2(data->key);
185         switch (data->type) {
186         case RD_I_VAL:
187             if (isnan(data->u_val)) {
188                 rb_hash_aset(result, key, Qnil);
189             }
190             else {
191                 rb_hash_aset(result, key, rb_float_new(data->u_val));
192             }
193             break;
194         case RD_I_CNT:
195             rb_hash_aset(result, key, INT2FIX(data->u_cnt));
196             break;
197         case RD_I_STR:
198             rb_hash_aset(result, key, rb_str_new2(data->u_str));
199             free(data->u_str);
200             break;
201         }
202         p = data;
203         data = data->next;
204         free(p);
205     }
206     return result;
207 }
208 */
209
210 VALUE rb_rrd_last(VALUE self, VALUE args)
211 {
212     string_arr a;
213     time_t last;
214
215     a = string_arr_new(args);
216     reset_rrd_state();
217     last = rrd_last(a.len, a.strings);
218     string_arr_delete(a);
219
220     RRD_CHECK_ERROR
221
222     return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
223 }
224
225 VALUE rb_rrd_resize(VALUE self, VALUE args)
226 {
227     return rrd_call(rrd_resize, args);
228 }
229
230 VALUE rb_rrd_restore(VALUE self, VALUE args)
231 {
232     return rrd_call(rrd_restore, args);
233 }
234
235 VALUE rb_rrd_tune(VALUE self, VALUE args)
236 {
237     return rrd_call(rrd_tune, args);
238 }
239
240 VALUE rb_rrd_update(VALUE self, VALUE args)
241 {
242     return rrd_call(rrd_update, args);
243 }
244
245 void Init_RRD() 
246 {
247     mRRD = rb_define_module("RRD");
248     rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
249
250     rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
251     rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
252     rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
253     rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
254     rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
255     rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
256     rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
257     rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
258     rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
259 }