1 /*
2 * tclrrd.c -- A TCL interpreter extension to access the RRD library.
3 *
4 * Copyright (c) 1999,2000 Frank Strauss, Technical University of Braunschweig.
5 *
6 * See the file "COPYING" for information on usage and redistribution
7 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
8 *
9 * $Id$
10 */
14 #include <time.h>
15 #include <tcl.h>
16 #include <rrd_tool.h>
17 #include <rrd_format.h>
21 extern int __getopt_initialized;
24 /*
25 * some rrd_XXX() functions might modify the argv strings passed to it.
26 * Furthermore, they use getopt() without initializing getopt's optind
27 * variable themselves. Hence, we need to do some preparation before
28 * calling the rrd library functions.
29 */
30 static char ** getopt_init(argc, argv)
31 int argc;
32 char *argv[];
33 {
34 char **argv2;
35 int i;
37 optind = 0;
39 argv2 = calloc(argc, sizeof(char *));
40 for (i = 0; i < argc; i++) {
41 argv2[i] = strdup(argv[i]);
42 }
43 return argv2;
44 }
46 static void getopt_cleanup(argc, argv2)
47 int argc;
48 char *argv2[];
49 {
50 int i;
52 for (i = 0; i < argc; i++) {
53 free(argv2[i]);
54 }
55 free(argv2);
56 }
60 static int
61 Rrd_Create(clientData, interp, argc, argv)
62 ClientData clientData;
63 Tcl_Interp *interp;
64 int argc;
65 char *argv[];
66 {
67 char **argv2;
69 argv2 = getopt_init(argc, argv);
70 rrd_create(argc, argv2);
71 getopt_cleanup(argc, argv2);
73 if (rrd_test_error()) {
74 Tcl_AppendResult(interp, "RRD Error: ",
75 rrd_get_error(), (char *) NULL);
76 rrd_clear_error();
77 return TCL_ERROR;
78 }
80 return TCL_OK;
81 }
85 static int
86 Rrd_Dump(clientData, interp, argc, argv)
87 ClientData clientData;
88 Tcl_Interp *interp;
89 int argc;
90 char *argv[];
91 {
92 char **argv2;
94 argv2 = getopt_init(argc, argv);
95 rrd_dump(argc, argv2);
96 getopt_cleanup(argv, argv2);
98 /* NOTE: rrd_dump() writes to stdout. No interaction with TCL. */
100 if (rrd_test_error()) {
101 Tcl_AppendResult(interp, "RRD Error: ",
102 rrd_get_error(), (char *) NULL);
103 rrd_clear_error();
104 return TCL_ERROR;
105 }
107 return TCL_OK;
108 }
112 static int
113 Rrd_Last(clientData, interp, argc, argv)
114 ClientData clientData;
115 Tcl_Interp *interp;
116 int argc;
117 char *argv[];
118 {
119 time_t t;
120 char **argv2;
122 argv2 = getopt_init(argc, argv);
123 t = rrd_last(argc, argv2);
124 getopt_cleanup(argv, argv2);
127 if (rrd_test_error()) {
128 Tcl_AppendResult(interp, "RRD Error: ",
129 rrd_get_error(), (char *) NULL);
130 rrd_clear_error();
131 return TCL_ERROR;
132 }
134 Tcl_SetIntObj(Tcl_GetObjResult(interp), t);
136 return TCL_OK;
137 }
141 static int
142 Rrd_Update(clientData, interp, argc, argv)
143 ClientData clientData;
144 Tcl_Interp *interp;
145 int argc;
146 char *argv[];
147 {
148 char **argv2;
150 argv2 = getopt_init(argc, argv);
151 rrd_update(argc, argv2);
152 getopt_cleanup(argv, argv2);
154 if (rrd_test_error()) {
155 Tcl_AppendResult(interp, "RRD Error: ",
156 rrd_get_error(), (char *) NULL);
157 rrd_clear_error();
158 return TCL_ERROR;
159 }
161 return TCL_OK;
162 }
166 static int
167 Rrd_Fetch(clientData, interp, argc, argv)
168 ClientData clientData;
169 Tcl_Interp *interp;
170 int argc;
171 char *argv[];
172 {
173 time_t start, end;
174 unsigned long step, ds_cnt, i, ii;
175 rrd_value_t *data, *datai;
176 char **ds_namv;
177 Tcl_Obj *listPtr;
178 char s[30];
179 char **argv2;
181 argv2 = getopt_init(argc, argv);
182 if (rrd_fetch(argc, argv2, &start, &end, &step,
183 &ds_cnt, &ds_namv, &data) != -1) {
184 datai = data;
185 listPtr = Tcl_GetObjResult(interp);
186 for (i = start; i <= end; i += step) {
187 for (ii = 0; ii < ds_cnt; ii++) {
188 sprintf(s, "%.2f", *(datai++));
189 Tcl_ListObjAppendElement(interp, listPtr,
190 Tcl_NewStringObj(s, -1));
191 }
192 }
193 for (i=0; i<ds_cnt; i++) free(ds_namv[i]);
194 free(ds_namv);
195 free(data);
196 }
197 getopt_cleanup(argv, argv2);
199 if (rrd_test_error()) {
200 Tcl_AppendResult(interp, "RRD Error: ",
201 rrd_get_error(), (char *) NULL);
202 rrd_clear_error();
203 return TCL_ERROR;
204 }
206 return TCL_OK;
207 }
211 static int
212 Rrd_Graph(clientData, interp, argc, argv)
213 ClientData clientData;
214 Tcl_Interp *interp;
215 int argc;
216 char *argv[];
217 {
218 char **calcpr;
219 int xsize, ysize;
220 double ymin, ymax;
221 Tcl_Obj *listPtr;
222 char **argv2;
224 calcpr = NULL;
226 argv2 = getopt_init(argc, argv);
227 if (rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
228 listPtr = Tcl_GetObjResult(interp);
229 Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(xsize));
230 Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(ysize));
231 if (calcpr) {
232 #if 0
233 int i;
235 for(i = 0; calcpr[i]; i++){
236 printf("%s\n", calcpr[i]);
237 free(calcpr[i]);
238 }
239 #endif
240 free(calcpr);
241 }
242 }
243 getopt_cleanup(argv, argv2);
245 if (rrd_test_error()) {
246 Tcl_AppendResult(interp, "RRD Error: ",
247 rrd_get_error(), (char *) NULL);
248 rrd_clear_error();
249 return TCL_ERROR;
250 }
252 return TCL_OK;
253 }
257 static int
258 Rrd_Tune(clientData, interp, argc, argv)
259 ClientData clientData;
260 Tcl_Interp *interp;
261 int argc;
262 char *argv[];
263 {
264 char **argv2;
266 argv2 = getopt_init(argc, argv);
267 rrd_tune(argc, argv2);
268 getopt_cleanup(argv, argv2);
270 if (rrd_test_error()) {
271 Tcl_AppendResult(interp, "RRD Error: ",
272 rrd_get_error(), (char *) NULL);
273 rrd_clear_error();
274 return TCL_ERROR;
275 }
277 return TCL_OK;
278 }
282 static int
283 Rrd_Resize(clientData, interp, argc, argv)
284 ClientData clientData;
285 Tcl_Interp *interp;
286 int argc;
287 char *argv[];
288 {
289 char **argv2;
291 argv2 = getopt_init(argc, argv);
292 rrd_resize(argc, argv2);
293 getopt_cleanup(argv, argv2);
295 if (rrd_test_error()) {
296 Tcl_AppendResult(interp, "RRD Error: ",
297 rrd_get_error(), (char *) NULL);
298 rrd_clear_error();
299 return TCL_ERROR;
300 }
302 return TCL_OK;
303 }
307 static int
308 Rrd_Restore(clientData, interp, argc, argv)
309 ClientData clientData;
310 Tcl_Interp *interp;
311 int argc;
312 char *argv[];
313 {
314 char **argv2;
316 argv2 = getopt_init(argc, argv);
317 rrd_restore(argc, argv2);
318 getopt_cleanup(argv, argv2);
320 if (rrd_test_error()) {
321 Tcl_AppendResult(interp, "RRD Error: ",
322 rrd_get_error(), (char *) NULL);
323 rrd_clear_error();
324 return TCL_ERROR;
325 }
327 return TCL_OK;
328 }
332 /*
333 * The following structure defines the commands in the Rrd extension.
334 */
336 typedef struct {
337 char *name; /* Name of the command. */
338 Tcl_CmdProc *proc; /* Procedure for command. */
339 } CmdInfo;
341 static CmdInfo rrdCmds[] = {
342 { "Rrd::create", Rrd_Create },
343 { "Rrd::dump", Rrd_Dump },
344 { "Rrd::last", Rrd_Last },
345 { "Rrd::update", Rrd_Update },
346 { "Rrd::fetch", Rrd_Fetch },
347 { "Rrd::graph", Rrd_Graph },
348 { "Rrd::tune", Rrd_Tune },
349 { "Rrd::resize", Rrd_Resize },
350 { "Rrd::restore", Rrd_Restore },
351 { (char *) NULL, (Tcl_CmdProc *) NULL }
352 };
356 int
357 Tclrrd_Init(interp, safe)
358 Tcl_Interp *interp;
359 int safe;
360 {
361 CmdInfo *cmdInfoPtr;
362 Tcl_CmdInfo info;
364 if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
365 return TCL_ERROR;
366 }
368 Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY);
370 for (cmdInfoPtr = rrdCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
371 /*
372 * Check if the command already exists and return an error
373 * to ensure we detect name clashes while loading the Rrd
374 * extension.
375 */
376 if (Tcl_GetCommandInfo(interp, cmdInfoPtr->name, &info)) {
377 Tcl_AppendResult(interp, "command \"", cmdInfoPtr->name,
378 "\" already exists", (char *) NULL);
379 return TCL_ERROR;
380 }
381 Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc,
382 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
383 }
385 if (Tcl_PkgProvide(interp, "Rrd", VERSION) != TCL_OK) {
386 return TCL_ERROR;
387 }
389 return TCL_OK;
390 }