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>
19 extern int Tclrrd_Init(Tcl_Interp *interp, int safe);
21 extern int __getopt_initialized;
24 /*
25 * some rrd_XXX() functions might modify the argv strings passed to it.
26 * Hence, we need to do some preparation before
27 * calling the rrd library functions.
28 */
29 static char ** getopt_init(argc, argv)
30 int argc;
31 char *argv[];
32 {
33 char **argv2;
34 int i;
36 argv2 = calloc(argc, sizeof(char *));
37 for (i = 0; i < argc; i++) {
38 argv2[i] = strdup(argv[i]);
39 }
40 return argv2;
41 }
43 static void getopt_cleanup(argc, argv2)
44 int argc;
45 char *argv2[];
46 {
47 int i;
49 for (i = 0; i < argc; i++) {
50 free(argv2[i]);
51 }
52 free(argv2);
53 }
57 static int
58 Rrd_Create(clientData, interp, argc, argv)
59 ClientData clientData;
60 Tcl_Interp *interp;
61 int argc;
62 char *argv[];
63 {
64 char **argv2;
66 argv2 = getopt_init(argc, argv);
67 rrd_create(argc, argv2);
68 getopt_cleanup(argc, argv2);
70 if (rrd_test_error()) {
71 Tcl_AppendResult(interp, "RRD Error: ",
72 rrd_get_error(), (char *) NULL);
73 rrd_clear_error();
74 return TCL_ERROR;
75 }
77 return TCL_OK;
78 }
82 static int
83 Rrd_Dump(clientData, interp, argc, argv)
84 ClientData clientData;
85 Tcl_Interp *interp;
86 int argc;
87 char *argv[];
88 {
89 char **argv2;
91 argv2 = getopt_init(argc, argv);
92 rrd_dump(argc, argv2);
93 getopt_cleanup(argv, argv2);
95 /* NOTE: rrd_dump() writes to stdout. No interaction with TCL. */
97 if (rrd_test_error()) {
98 Tcl_AppendResult(interp, "RRD Error: ",
99 rrd_get_error(), (char *) NULL);
100 rrd_clear_error();
101 return TCL_ERROR;
102 }
104 return TCL_OK;
105 }
109 static int
110 Rrd_Last(clientData, interp, argc, argv)
111 ClientData clientData;
112 Tcl_Interp *interp;
113 int argc;
114 char *argv[];
115 {
116 time_t t;
117 char **argv2;
119 argv2 = getopt_init(argc, argv);
120 t = rrd_last(argc, argv2);
121 getopt_cleanup(argv, argv2);
124 if (rrd_test_error()) {
125 Tcl_AppendResult(interp, "RRD Error: ",
126 rrd_get_error(), (char *) NULL);
127 rrd_clear_error();
128 return TCL_ERROR;
129 }
131 Tcl_SetIntObj(Tcl_GetObjResult(interp), t);
133 return TCL_OK;
134 }
138 static int
139 Rrd_Update(clientData, interp, argc, argv)
140 ClientData clientData;
141 Tcl_Interp *interp;
142 int argc;
143 char *argv[];
144 {
145 char **argv2;
147 argv2 = getopt_init(argc, argv);
148 rrd_update(argc, argv2);
149 getopt_cleanup(argv, argv2);
151 if (rrd_test_error()) {
152 Tcl_AppendResult(interp, "RRD Error: ",
153 rrd_get_error(), (char *) NULL);
154 rrd_clear_error();
155 return TCL_ERROR;
156 }
158 return TCL_OK;
159 }
163 static int
164 Rrd_Fetch(clientData, interp, argc, argv)
165 ClientData clientData;
166 Tcl_Interp *interp;
167 int argc;
168 char *argv[];
169 {
170 time_t start, end, j;
171 unsigned long step, ds_cnt, i, ii;
172 rrd_value_t *data, *datai;
173 char **ds_namv;
174 Tcl_Obj *listPtr;
175 char s[30];
176 char **argv2;
178 argv2 = getopt_init(argc, argv);
179 if (rrd_fetch(argc, argv2, &start, &end, &step,
180 &ds_cnt, &ds_namv, &data) != -1) {
181 datai = data;
182 listPtr = Tcl_GetObjResult(interp);
183 for (j = start; j <= end; j += step) {
184 for (ii = 0; ii < ds_cnt; ii++) {
185 sprintf(s, "%.2f", *(datai++));
186 Tcl_ListObjAppendElement(interp, listPtr,
187 Tcl_NewStringObj(s, -1));
188 }
189 }
190 for (i=0; i<ds_cnt; i++) free(ds_namv[i]);
191 free(ds_namv);
192 free(data);
193 }
194 getopt_cleanup(argv, argv2);
196 if (rrd_test_error()) {
197 Tcl_AppendResult(interp, "RRD Error: ",
198 rrd_get_error(), (char *) NULL);
199 rrd_clear_error();
200 return TCL_ERROR;
201 }
203 return TCL_OK;
204 }
208 static int
209 Rrd_Graph(clientData, interp, argc, argv)
210 ClientData clientData;
211 Tcl_Interp *interp;
212 int argc;
213 char *argv[];
214 {
215 char **calcpr;
216 int xsize, ysize;
217 double ymin, ymax;
218 Tcl_Obj *listPtr;
219 char **argv2;
221 calcpr = NULL;
223 argv2 = getopt_init(argc, argv);
224 if (rrd_graph(argc, argv2, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
225 listPtr = Tcl_GetObjResult(interp);
226 Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(xsize));
227 Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(ysize));
228 if (calcpr) {
229 #if 0
230 int i;
232 for(i = 0; calcpr[i]; i++){
233 printf("%s\n", calcpr[i]);
234 free(calcpr[i]);
235 }
236 #endif
237 free(calcpr);
238 }
239 }
240 getopt_cleanup(argv, argv2);
242 if (rrd_test_error()) {
243 Tcl_AppendResult(interp, "RRD Error: ",
244 rrd_get_error(), (char *) NULL);
245 rrd_clear_error();
246 return TCL_ERROR;
247 }
249 return TCL_OK;
250 }
254 static int
255 Rrd_Tune(clientData, interp, argc, argv)
256 ClientData clientData;
257 Tcl_Interp *interp;
258 int argc;
259 char *argv[];
260 {
261 char **argv2;
263 argv2 = getopt_init(argc, argv);
264 rrd_tune(argc, argv2);
265 getopt_cleanup(argv, argv2);
267 if (rrd_test_error()) {
268 Tcl_AppendResult(interp, "RRD Error: ",
269 rrd_get_error(), (char *) NULL);
270 rrd_clear_error();
271 return TCL_ERROR;
272 }
274 return TCL_OK;
275 }
279 static int
280 Rrd_Resize(clientData, interp, argc, argv)
281 ClientData clientData;
282 Tcl_Interp *interp;
283 int argc;
284 char *argv[];
285 {
286 char **argv2;
288 argv2 = getopt_init(argc, argv);
289 rrd_resize(argc, argv2);
290 getopt_cleanup(argv, argv2);
292 if (rrd_test_error()) {
293 Tcl_AppendResult(interp, "RRD Error: ",
294 rrd_get_error(), (char *) NULL);
295 rrd_clear_error();
296 return TCL_ERROR;
297 }
299 return TCL_OK;
300 }
304 static int
305 Rrd_Restore(clientData, interp, argc, argv)
306 ClientData clientData;
307 Tcl_Interp *interp;
308 int argc;
309 char *argv[];
310 {
311 char **argv2;
313 argv2 = getopt_init(argc, argv);
314 rrd_restore(argc, argv2);
315 getopt_cleanup(argv, argv2);
317 if (rrd_test_error()) {
318 Tcl_AppendResult(interp, "RRD Error: ",
319 rrd_get_error(), (char *) NULL);
320 rrd_clear_error();
321 return TCL_ERROR;
322 }
324 return TCL_OK;
325 }
329 /*
330 * The following structure defines the commands in the Rrd extension.
331 */
333 typedef struct {
334 char *name; /* Name of the command. */
335 Tcl_CmdProc *proc; /* Procedure for command. */
336 } CmdInfo;
338 static CmdInfo rrdCmds[] = {
339 { "Rrd::create", Rrd_Create },
340 { "Rrd::dump", Rrd_Dump },
341 { "Rrd::last", Rrd_Last },
342 { "Rrd::update", Rrd_Update },
343 { "Rrd::fetch", Rrd_Fetch },
344 { "Rrd::graph", Rrd_Graph },
345 { "Rrd::tune", Rrd_Tune },
346 { "Rrd::resize", Rrd_Resize },
347 { "Rrd::restore", Rrd_Restore },
348 { (char *) NULL, (Tcl_CmdProc *) NULL }
349 };
353 int
354 Tclrrd_Init(interp, safe)
355 Tcl_Interp *interp;
356 int safe;
357 {
358 CmdInfo *cmdInfoPtr;
359 Tcl_CmdInfo info;
361 if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
362 return TCL_ERROR;
363 }
365 Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY);
367 for (cmdInfoPtr = rrdCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
368 /*
369 * Check if the command already exists and return an error
370 * to ensure we detect name clashes while loading the Rrd
371 * extension.
372 */
373 if (Tcl_GetCommandInfo(interp, cmdInfoPtr->name, &info)) {
374 Tcl_AppendResult(interp, "command \"", cmdInfoPtr->name,
375 "\" already exists", (char *) NULL);
376 return TCL_ERROR;
377 }
378 Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc,
379 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
380 }
382 if (Tcl_PkgProvide(interp, "Rrd", VERSION) != TCL_OK) {
383 return TCL_ERROR;
384 }
386 return TCL_OK;
387 }