aa082dda0caf439d9a5a21f4a9f0f4e16e25e9e3
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, "invalid argument - %s, expected T_STRING or T_FIXNUM on index %d", rb_class2name(CLASS_OF(v)), i);
53 break;
54 }
55 }
57 return a;
58 }
60 void string_arr_delete(
61 string_arr a)
62 {
63 int i;
65 /* skip dummy first entry */
66 for (i = 1; i < a.len; i++) {
67 free(a.strings[i]);
68 }
70 free(a.strings);
71 }
73 void reset_rrd_state(
74 )
75 {
76 optind = 0;
77 opterr = 0;
78 rrd_clear_error();
79 }
81 VALUE rrd_call(
82 RRDFUNC func,
83 VALUE args)
84 {
85 string_arr a;
87 a = string_arr_new(args);
88 reset_rrd_state();
89 func(a.len, a.strings);
90 string_arr_delete(a);
92 RRD_CHECK_ERROR return Qnil;
93 }
95 VALUE rb_rrd_create(
96 VALUE self,
97 VALUE args)
98 {
99 return rrd_call(rrd_create, args);
100 }
102 VALUE rb_rrd_dump(
103 VALUE self,
104 VALUE args)
105 {
106 return rrd_call(rrd_dump, args);
107 }
109 VALUE rb_rrd_fetch(
110 VALUE self,
111 VALUE args)
112 {
113 string_arr a;
114 unsigned long i, j, k, step, ds_cnt;
115 rrd_value_t *raw_data;
116 char **raw_names;
117 VALUE data, names, result;
118 time_t start, end;
120 a = string_arr_new(args);
121 reset_rrd_state();
122 rrd_fetch(a.len, a.strings, &start, &end, &step, &ds_cnt, &raw_names,
123 &raw_data);
124 string_arr_delete(a);
126 RRD_CHECK_ERROR names = rb_ary_new();
128 for (i = 0; i < ds_cnt; i++) {
129 rb_ary_push(names, rb_str_new2(raw_names[i]));
130 free(raw_names[i]);
131 }
132 free(raw_names);
134 k = 0;
135 data = rb_ary_new();
136 for (i = start; i <= end; i += step) {
137 VALUE line = rb_ary_new2(ds_cnt);
139 for (j = 0; j < ds_cnt; j++) {
140 rb_ary_store(line, j, rb_float_new(raw_data[k]));
141 k++;
142 }
143 rb_ary_push(data, line);
144 }
145 free(raw_data);
147 result = rb_ary_new2(4);
148 rb_ary_store(result, 0, INT2FIX(start));
149 rb_ary_store(result, 1, INT2FIX(end));
150 rb_ary_store(result, 2, names);
151 rb_ary_store(result, 2, data);
152 return result;
153 }
155 VALUE rb_rrd_graph(
156 VALUE self,
157 VALUE args)
158 {
159 string_arr a;
160 char **calcpr, **p;
161 VALUE result, print_results;
162 int xsize, ysize;
163 double ymin, ymax;
165 a = string_arr_new(args);
166 reset_rrd_state();
167 rrd_graph(a.len, a.strings, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
168 string_arr_delete(a);
170 RRD_CHECK_ERROR result = rb_ary_new2(3);
172 print_results = rb_ary_new();
173 p = calcpr;
174 for (p = calcpr; p && *p; p++) {
175 rb_ary_push(print_results, rb_str_new2(*p));
176 free(*p);
177 }
178 free(calcpr);
179 rb_ary_store(result, 0, print_results);
180 rb_ary_store(result, 1, INT2FIX(xsize));
181 rb_ary_store(result, 2, INT2FIX(ysize));
182 return result;
183 }
185 /*
186 VALUE rb_rrd_info(VALUE self, VALUE args)
187 {
188 string_arr a;
189 info_t *p;
190 VALUE result;
192 a = string_arr_new(args);
193 data = rrd_info(a.len, a.strings);
194 string_arr_delete(a);
196 RRD_CHECK_ERROR
198 result = rb_hash_new();
199 while (data) {
200 VALUE key = rb_str_new2(data->key);
201 switch (data->type) {
202 case RD_I_VAL:
203 if (isnan(data->u_val)) {
204 rb_hash_aset(result, key, Qnil);
205 }
206 else {
207 rb_hash_aset(result, key, rb_float_new(data->u_val));
208 }
209 break;
210 case RD_I_CNT:
211 rb_hash_aset(result, key, INT2FIX(data->u_cnt));
212 break;
213 case RD_I_STR:
214 rb_hash_aset(result, key, rb_str_new2(data->u_str));
215 free(data->u_str);
216 break;
217 }
218 p = data;
219 data = data->next;
220 free(p);
221 }
222 return result;
223 }
224 */
226 VALUE rb_rrd_last(
227 VALUE self,
228 VALUE args)
229 {
230 string_arr a;
231 time_t last;
233 a = string_arr_new(args);
234 reset_rrd_state();
235 last = rrd_last(a.len, a.strings);
236 string_arr_delete(a);
238 RRD_CHECK_ERROR
239 return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
240 }
242 VALUE rb_rrd_resize(
243 VALUE self,
244 VALUE args)
245 {
246 return rrd_call(rrd_resize, args);
247 }
249 VALUE rb_rrd_restore(
250 VALUE self,
251 VALUE args)
252 {
253 return rrd_call(rrd_restore, args);
254 }
256 VALUE rb_rrd_tune(
257 VALUE self,
258 VALUE args)
259 {
260 return rrd_call(rrd_tune, args);
261 }
263 VALUE rb_rrd_update(
264 VALUE self,
265 VALUE args)
266 {
267 return rrd_call(rrd_update, args);
268 }
270 void Init_RRD(
271 )
272 {
273 mRRD = rb_define_module("RRD");
274 rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
276 rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
277 rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
278 rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
279 rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
280 rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
281 rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
282 rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
283 rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
284 rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
285 }