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 (*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();
23 string_arr string_arr_new(VALUE rb_strings)
24 {
25 string_arr a;
26 char buf[64];
27 int i;
29 Check_Type(rb_strings, T_ARRAY);
30 a.len = RARRAY(rb_strings)->len + 1;
32 a.strings = malloc(a.len * sizeof(char *));
33 a.strings[0] = "dummy"; /* first element is a dummy element */
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 }
51 return a;
52 }
54 void string_arr_delete(string_arr a)
55 {
56 int i;
58 /* skip dummy first entry */
59 for (i = 1; i < a.len; i++) {
60 free(a.strings[i]);
61 }
63 free(a.strings);
64 }
66 void reset_rrd_state()
67 {
68 optind = 0;
69 opterr = 0;
70 rrd_clear_error();
71 }
73 VALUE rrd_call(RRDFUNC func, VALUE args)
74 {
75 string_arr a;
77 a = string_arr_new(args);
78 reset_rrd_state();
79 func(a.len, a.strings);
80 string_arr_delete(a);
82 RRD_CHECK_ERROR
84 return Qnil;
85 }
87 VALUE rb_rrd_create(VALUE self, VALUE args)
88 {
89 return rrd_call(rrd_create, args);
90 }
92 VALUE rb_rrd_dump(VALUE self, VALUE args)
93 {
94 return rrd_call(rrd_dump, args);
95 }
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;
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);
111 RRD_CHECK_ERROR
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);
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);
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 }
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;
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);
153 RRD_CHECK_ERROR
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 }
169 /*
170 VALUE rb_rrd_info(VALUE self, VALUE args)
171 {
172 string_arr a;
173 info_t *p;
174 VALUE result;
176 a = string_arr_new(args);
177 data = rrd_info(a.len, a.strings);
178 string_arr_delete(a);
180 RRD_CHECK_ERROR
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 */
210 VALUE rb_rrd_last(VALUE self, VALUE args)
211 {
212 string_arr a;
213 time_t last;
215 a = string_arr_new(args);
216 reset_rrd_state();
217 last = rrd_last(a.len, a.strings);
218 string_arr_delete(a);
220 RRD_CHECK_ERROR
222 return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
223 }
225 VALUE rb_rrd_resize(VALUE self, VALUE args)
226 {
227 return rrd_call(rrd_resize, args);
228 }
230 VALUE rb_rrd_restore(VALUE self, VALUE args)
231 {
232 return rrd_call(rrd_restore, args);
233 }
235 VALUE rb_rrd_tune(VALUE self, VALUE args)
236 {
237 return rrd_call(rrd_tune, args);
238 }
240 VALUE rb_rrd_update(VALUE self, VALUE args)
241 {
242 return rrd_call(rrd_update, args);
243 }
245 void Init_RRD()
246 {
247 mRRD = rb_define_module("RRD");
248 rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
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 }