8a762ada459201a2d86e9194f6cb60ca449dce77
1 /* $Id: main.c 1212 2007-11-08 10:13:48Z oetiker $
2 * Substantial penalty for early withdrawal.
3 */
5 #include <unistd.h>
6 #include <ruby.h>
7 #include "../../src/rrd_tool.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 - %s, expected T_STRING or T_FIXNUM on index %d", rb_class2name(CLASS_OF(v)), i);
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, INT2NUM(start));
134 rb_ary_store(result, 1, INT2NUM(end));
135 rb_ary_store(result, 2, names);
136 rb_ary_store(result, 3, 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 VALUE rb_rrd_info(VALUE self, VALUE args)
170 {
171 string_arr a;
172 info_t *p, *data;
173 VALUE result;
175 a = string_arr_new(args);
176 data = rrd_info(a.len, a.strings);
177 string_arr_delete(a);
179 RRD_CHECK_ERROR
181 result = rb_hash_new();
182 while (data) {
183 VALUE key = rb_str_new2(data->key);
184 switch (data->type) {
185 case RD_I_VAL:
186 if (isnan(data->value.u_val)) {
187 rb_hash_aset(result, key, Qnil);
188 }
189 else {
190 rb_hash_aset(result, key, rb_float_new(data->value.u_val));
191 }
192 break;
193 case RD_I_CNT:
194 rb_hash_aset(result, key, INT2FIX(data->value.u_cnt));
195 break;
196 case RD_I_STR:
197 rb_hash_aset(result, key, rb_str_new2(data->value.u_str));
198 free(data->value.u_str);
199 break;
200 }
201 p = data;
202 data = data->next;
203 free(p);
204 }
205 return result;
206 }
208 VALUE rb_rrd_last(VALUE self, VALUE args)
209 {
210 string_arr a;
211 time_t last;
213 a = string_arr_new(args);
214 reset_rrd_state();
215 last = rrd_last(a.len, a.strings);
216 string_arr_delete(a);
218 RRD_CHECK_ERROR
220 return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
221 }
223 VALUE rb_rrd_resize(VALUE self, VALUE args)
224 {
225 return rrd_call(rrd_resize, args);
226 }
228 VALUE rb_rrd_restore(VALUE self, VALUE args)
229 {
230 return rrd_call(rrd_restore, args);
231 }
233 VALUE rb_rrd_tune(VALUE self, VALUE args)
234 {
235 return rrd_call(rrd_tune, args);
236 }
238 VALUE rb_rrd_update(VALUE self, VALUE args)
239 {
240 return rrd_call(rrd_update, args);
241 }
243 void Init_RRD()
244 {
245 mRRD = rb_define_module("RRD");
246 rb_eRRDError = rb_define_class("RRDError", rb_eStandardError);
248 rb_define_module_function(mRRD, "create", rb_rrd_create, -2);
249 rb_define_module_function(mRRD, "dump", rb_rrd_dump, -2);
250 rb_define_module_function(mRRD, "fetch", rb_rrd_fetch, -2);
251 rb_define_module_function(mRRD, "graph", rb_rrd_graph, -2);
252 rb_define_module_function(mRRD, "last", rb_rrd_last, -2);
253 rb_define_module_function(mRRD, "resize", rb_rrd_resize, -2);
254 rb_define_module_function(mRRD, "restore", rb_rrd_restore, -2);
255 rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2);
256 rb_define_module_function(mRRD, "update", rb_rrd_update, -2);
257 rb_define_module_function(mRRD, "info", rb_rrd_info, -2);
258 }