1 /* $Id$
2 * Substantial penalty for early withdrawal.
3 */
5 #include <unistd.h>
6 #include <ruby.h>
7 #include <rrd.h>
9 typedef struct string_arr_t {
10 int len;
11 char **strings;
12 } string_arr;
14 VALUE mRRD;
15 VALUE rb_eRRDError;
17 typedef int (
18 *RRDFUNC) (
19 int argc,
20 char **argv);
22 #define RRD_CHECK_ERROR \
23 if (rrd_test_error()) \
24 rb_raise(rb_eRRDError, rrd_get_error()); \
25 rrd_clear_error();
27 string_arr string_arr_new(
28 VALUE rb_strings)
29 {
30 string_arr a;
31 char buf[64];
32 int i;
34 Check_Type(rb_strings, T_ARRAY);
35 a.len = RARRAY(rb_strings)->len + 1;
37 a.strings = malloc(a.len * sizeof(char *));
38 a.strings[0] = "dummy"; /* first element is a dummy element */
40 for (i = 0; i < a.len - 1; i++) {
41 VALUE v = rb_ary_entry(rb_strings, i);
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 }
59 return a;
60 }
62 void string_arr_delete(
63 string_arr a)
64 {
65 int i;
67 /* skip dummy first entry */
68 for (i = 1; i < a.len; i++) {
69 free(a.strings[i]);
70 }
72 free(a.strings);
73 }
75 void reset_rrd_state(
76 )
77 {
78 optind = 0;
79 opterr = 0;
80 rrd_clear_error();
81 }
83 VALUE rrd_call(
84 RRDFUNC func,
85 VALUE args)
86 {
87 string_arr a;
89 a = string_arr_new(args);
90 reset_rrd_state();
91 func(a.len, a.strings);
92 string_arr_delete(a);
94 RRD_CHECK_ERROR return Qnil;
95 }
97 VALUE rb_rrd_create(
98 VALUE self,
99 VALUE args)
100 {
101 return rrd_call(rrd_create, args);
102 }
104 VALUE rb_rrd_dump(
105 VALUE self,
106 VALUE args)
107 {
108 return rrd_call(rrd_dump, args);
109 }
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;
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);
128 RRD_CHECK_ERROR names = rb_ary_new();
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);
136 k = 0;
137 data = rb_ary_new();
138 for (i = start; i <= end; i += step) {
139 VALUE line = rb_ary_new2(ds_cnt);
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);
149 result = rb_ary_new2(4);
150 rb_ary_store(result, 0, INT2FIX(start));
151 rb_ary_store(result, 1, INT2FIX(end));
152 rb_ary_store(result, 2, names);
153 rb_ary_store(result, 2, data);
154 return result;
155 }
157 VALUE rb_rrd_graph(
158 VALUE self,
159 VALUE args)
160 {
161 string_arr a;
162 char **calcpr, **p;
163 VALUE result, print_results;
164 int xsize, ysize;
165 double ymin, ymax;
167 a = string_arr_new(args);
168 reset_rrd_state();
169 rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
170 string_arr_delete(a);
172 RRD_CHECK_ERROR result = rb_ary_new2(3);
174 print_results = rb_ary_new();
175 p = calcpr;
176 for (p = calcpr; p && *p; p++) {
177 rb_ary_push(print_results, rb_str_new2(*p));
178 free(*p);
179 }
180 free(calcpr);
181 rb_ary_store(result, 0, print_results);
182 rb_ary_store(result, 1, INT2FIX(xsize));
183 rb_ary_store(result, 2, INT2FIX(ysize));
184 return result;
185 }
187 /*
188 VALUE rb_rrd_info(VALUE self, VALUE args)
189 {
190 string_arr a;
191 info_t *p;
192 VALUE result;
194 a = string_arr_new(args);
195 data = rrd_info(a.len, a.strings);
196 string_arr_delete(a);
198 RRD_CHECK_ERROR
200 result = rb_hash_new();
201 while (data) {
202 VALUE key = rb_str_new2(data->key);
203 switch (data->type) {
204 case RD_I_VAL:
205 if (isnan(data->u_val)) {
206 rb_hash_aset(result, key, Qnil);
207 }
208 else {
209 rb_hash_aset(result, key, rb_float_new(data->u_val));
210 }
211 break;
212 case RD_I_CNT:
213 rb_hash_aset(result, key, INT2FIX(data->u_cnt));
214 break;
215 case RD_I_STR:
216 rb_hash_aset(result, key, rb_str_new2(data->u_str));
217 free(data->u_str);
218 break;
219 }
220 p = data;
221 data = data->next;
222 free(p);
223 }
224 return result;
225 }
226 */
228 VALUE rb_rrd_last(
229 VALUE self,
230 VALUE args)
231 {
232 string_arr a;
233 time_t last;
235 a = string_arr_new(args);
236 reset_rrd_state();
237 last = rrd_last(a.len, a.strings);
238 string_arr_delete(a);
240 RRD_CHECK_ERROR
241 return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
242 }
244 VALUE rb_rrd_resize(
245 VALUE self,
246 VALUE args)
247 {
248 return rrd_call(rrd_resize, args);
249 }
251 VALUE rb_rrd_restore(
252 VALUE self,
253 VALUE args)
254 {
255 return rrd_call(rrd_restore, args);
256 }
258 VALUE rb_rrd_tune(
259 VALUE self,
260 VALUE args)
261 {
262 return rrd_call(rrd_tune, args);
263 }
265 VALUE rb_rrd_update(
266 VALUE self,
267 VALUE args)
268 {
269 return rrd_call(rrd_update, args);
270 }
272 void Init_RRD(
273 )
274 {
275 mRRD = rb_define_module("RRD");
276 rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
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 }