1 /* $Id$
2 * Substantial penalty for early withdrawal.
3 */
5 #include <unistd.h>
6 #include <ruby.h>
7 #include <math.h>
8 #include "../../src/rrd_tool.h"
10 typedef struct string_arr_t {
11 int len;
12 char **strings;
13 } string_arr;
15 VALUE mRRD;
16 VALUE rb_eRRDError;
18 typedef int (
19 *RRDFUNC) (
20 int argc,
21 char **argv);
23 typedef rrd_info_t *(
24 *RRDINFOFUNC) (
25 int argc,
26 char **argv);
28 #define RRD_CHECK_ERROR \
29 if (rrd_test_error()) \
30 rb_raise(rb_eRRDError, rrd_get_error()); \
31 rrd_clear_error();
33 string_arr string_arr_new(
34 VALUE rb_strings)
35 {
36 string_arr a;
37 char buf[64];
38 int i;
40 Check_Type(rb_strings, T_ARRAY);
41 a.len = RARRAY_LEN(rb_strings) + 1;
43 a.strings = malloc(a.len * sizeof(char *));
44 a.strings[0] = "dummy"; /* first element is a dummy element */
46 for (i = 0; i < a.len - 1; i++) {
47 VALUE v = rb_ary_entry(rb_strings, i);
49 switch (TYPE(v)) {
50 case T_STRING:
51 a.strings[i + 1] = strdup(StringValuePtr(v));
52 break;
53 case T_FIXNUM:
54 snprintf(buf, 63, "%d", FIX2INT(v));
55 a.strings[i + 1] = strdup(buf);
56 break;
57 default:
58 rb_raise(rb_eTypeError,
59 "invalid argument - %s, expected T_STRING or T_FIXNUM on index %d",
60 rb_class2name(CLASS_OF(v)), i);
61 break;
62 }
63 }
65 return a;
66 }
68 void string_arr_delete(
69 string_arr a)
70 {
71 int i;
73 /* skip dummy first entry */
74 for (i = 1; i < a.len; i++) {
75 free(a.strings[i]);
76 }
78 free(a.strings);
79 }
81 void reset_rrd_state(
82 )
83 {
84 optind = 0;
85 opterr = 0;
86 rrd_clear_error();
87 }
89 /* Simple Calls */
91 VALUE rrd_call(
92 RRDFUNC func,
93 VALUE args)
94 {
95 string_arr a;
97 a = string_arr_new(args);
98 reset_rrd_state();
99 func(a.len, a.strings);
100 string_arr_delete(a);
102 RRD_CHECK_ERROR return Qnil;
103 }
105 VALUE rb_rrd_create(
106 VALUE self,
107 VALUE args)
108 {
109 return rrd_call(rrd_create, args);
110 }
112 VALUE rb_rrd_dump(
113 VALUE self,
114 VALUE args)
115 {
116 return rrd_call(rrd_dump, args);
117 }
119 VALUE rb_rrd_resize(
120 VALUE self,
121 VALUE args)
122 {
123 return rrd_call(rrd_resize, args);
124 }
126 VALUE rb_rrd_restore(
127 VALUE self,
128 VALUE args)
129 {
130 return rrd_call(rrd_restore, args);
131 }
133 VALUE rb_rrd_tune(
134 VALUE self,
135 VALUE args)
136 {
137 return rrd_call(rrd_tune, args);
138 }
140 VALUE rb_rrd_update(
141 VALUE self,
142 VALUE args)
143 {
144 return rrd_call(rrd_update, args);
145 }
147 VALUE rb_rrd_flushcached(
148 VALUE self,
149 VALUE args)
150 {
151 return rrd_call(rrd_flushcached, args);
152 }
155 /* Calls Returning Data via the Info Interface */
157 VALUE rb_rrd_infocall(
158 RRDINFOFUNC func,
159 VALUE args)
160 {
161 string_arr a;
162 rrd_info_t *p, *data;
163 VALUE result;
165 a = string_arr_new(args);
166 reset_rrd_state();
167 data = func(a.len, a.strings);
168 string_arr_delete(a);
170 RRD_CHECK_ERROR result = rb_hash_new();
172 p = data;
173 while (data) {
174 VALUE key = rb_str_new2(data->key);
176 switch (data->type) {
177 case RD_I_VAL:
178 if (isnan(data->value.u_val)) {
179 rb_hash_aset(result, key, Qnil);
180 } else {
181 rb_hash_aset(result, key, rb_float_new(data->value.u_val));
182 }
183 break;
184 case RD_I_CNT:
185 rb_hash_aset(result, key, INT2FIX(data->value.u_cnt));
186 break;
187 case RD_I_STR:
188 rb_hash_aset(result, key, rb_str_new2(data->value.u_str));
189 break;
190 case RD_I_INT:
191 rb_hash_aset(result, key, INT2FIX(data->value.u_int));
192 break;
193 case RD_I_BLO:
194 rb_hash_aset(result, key,
195 rb_str_new((char *)data->value.u_blo.ptr,
196 data->value.u_blo.size));
197 break;
198 }
199 data = data->next;
200 }
201 rrd_info_free(p);
202 return result;
203 }
205 VALUE rb_rrd_info(
206 VALUE self,
207 VALUE args)
208 {
209 return rb_rrd_infocall(rrd_info, args);
210 }
212 VALUE rb_rrd_updatev(
213 VALUE self,
214 VALUE args)
215 {
216 return rb_rrd_infocall(rrd_update_v, args);
217 }
219 VALUE rb_rrd_graphv(
220 VALUE self,
221 VALUE args)
222 {
223 return rb_rrd_infocall(rrd_graph_v, args);
224 }
227 /* Other Calls */
229 VALUE rb_rrd_fetch(
230 VALUE self,
231 VALUE args)
232 {
233 string_arr a;
234 unsigned long i, j, k, step, ds_cnt;
235 rrd_value_t *raw_data;
236 char **raw_names;
237 VALUE data, names, result;
238 time_t start, end;
240 a = string_arr_new(args);
241 reset_rrd_state();
242 rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names,
243 &raw_data);
244 string_arr_delete(a);
246 RRD_CHECK_ERROR names = rb_ary_new();
248 for (i = 0; i < ds_cnt; i++) {
249 rb_ary_push(names, rb_str_new2(raw_names[i]));
250 rrd_freemem(raw_names[i]);
251 }
252 rrd_freemem(raw_names);
254 k = 0;
255 data = rb_ary_new();
256 for (i = start; i <= end; i += step) {
257 VALUE line = rb_ary_new2(ds_cnt);
259 for (j = 0; j < ds_cnt; j++) {
260 rb_ary_store(line, j, rb_float_new(raw_data[k]));
261 k++;
262 }
263 rb_ary_push(data, line);
264 }
265 rrd_freemem(raw_data);
267 result = rb_ary_new2(5);
268 rb_ary_store(result, 0, INT2NUM(start));
269 rb_ary_store(result, 1, INT2NUM(end));
270 rb_ary_store(result, 2, names);
271 rb_ary_store(result, 3, data);
272 rb_ary_store(result, 4, INT2FIX(step));
273 return result;
274 }
276 VALUE rb_rrd_graph(
277 VALUE self,
278 VALUE args)
279 {
280 string_arr a;
281 char **calcpr, **p;
282 VALUE result, print_results;
283 int xsize, ysize;
284 double ymin, ymax;
286 a = string_arr_new(args);
287 reset_rrd_state();
288 rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
289 string_arr_delete(a);
291 RRD_CHECK_ERROR result = rb_ary_new2(3);
293 print_results = rb_ary_new();
294 p = calcpr;
295 for (p = calcpr; p && *p; p++) {
296 rb_ary_push(print_results, rb_str_new2(*p));
297 rrd_freemem(*p);
298 }
299 rrd_freemem(calcpr);
300 rb_ary_store(result, 0, print_results);
301 rb_ary_store(result, 1, INT2FIX(xsize));
302 rb_ary_store(result, 2, INT2FIX(ysize));
303 return result;
304 }
307 VALUE rb_rrd_last(
308 VALUE self,
309 VALUE args)
310 {
311 string_arr a;
312 time_t last;
314 a = string_arr_new(args);
315 reset_rrd_state();
316 last = rrd_last(a.len, a.strings);
317 string_arr_delete(a);
319 RRD_CHECK_ERROR
320 return rb_funcall(rb_cTime, rb_intern("at"), 1, UINT2NUM(last));
321 }
323 VALUE rb_rrd_xport(
324 VALUE self,
325 VALUE args)
326 {
327 string_arr a;
328 unsigned long i, j, k, step, col_cnt;
329 int xxsize;
330 rrd_value_t *data;
331 char **legend_v;
332 VALUE legend, result, rdata;
333 time_t start, end;
335 a = string_arr_new(args);
336 rrd_xport(a.len, a.strings, &xxsize, &start, &end, &step, &col_cnt, &legend_v, &data);
337 string_arr_delete(a);
339 RRD_CHECK_ERROR;
341 legend = rb_ary_new();
342 for (i = 0; i < col_cnt; i++) {
343 rb_ary_push(legend, rb_str_new2(legend_v[i]));
344 free(legend_v[i]);
345 }
346 free(legend_v);
348 k = 0;
349 rdata = rb_ary_new();
350 for (i = start; i <= end; i += step) {
351 VALUE line = rb_ary_new2(col_cnt);
352 for (j = 0; j < col_cnt; j++) {
353 rb_ary_store(line, j, rb_float_new(data[k]));
354 k++;
355 }
356 rb_ary_push(rdata, line);
357 }
358 free(data);
360 result = rb_ary_new2(6);
361 rb_ary_store(result, 0, INT2FIX(start));
362 rb_ary_store(result, 1, INT2FIX(end));
363 rb_ary_store(result, 2, INT2FIX(step));
364 rb_ary_store(result, 3, INT2FIX(col_cnt));
365 rb_ary_store(result, 4, legend);
366 rb_ary_store(result, 5, rdata);
367 return result;
368 }
370 void Init_RRD(
371 )
372 {
373 mRRD = rb_define_module("RRD");
374 rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
376 rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
377 rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
378 rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
379 rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
380 rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
381 rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
382 rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
383 rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
384 rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
385 rb_define_module_function(mRRD, "flushcached", rb_rrd_flushcached, -2);
386 rb_define_module_function(mRRD, "info", rb_rrd_info, -2);
387 rb_define_module_function(mRRD, "updatev", rb_rrd_updatev, -2);
388 rb_define_module_function(mRRD, "graphv", rb_rrd_graphv, -2);
389 rb_define_module_function(mRRD, "xport", rb_rrd_xport, -2);
390 }