let rrd_graph return the actual value range it picked ...
[rrdtool.git] / bindings / tcl / tclrrd.c
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  */
11
12
13
14 #include <time.h>
15 #include <tcl.h>
16 #include <rrd_tool.h>
17 #include <rrd_format.h>
18
19
20
21 extern int __getopt_initialized;
22
23
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;
36     
37     optind = 0;
38
39     argv2 = calloc(argc, sizeof(char *));
40     for (i = 0; i < argc; i++) {
41         argv2[i] = strdup(argv[i]);
42     }
43     return argv2;
44 }
45
46 static void getopt_cleanup(argc, argv2)
47     int argc;
48     char *argv2[];
49 {
50     int i;
51     
52     for (i = 0; i < argc; i++) {
53         free(argv2[i]);
54     }
55     free(argv2);
56 }
57
58
59
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;
68
69     argv2 = getopt_init(argc, argv);
70     rrd_create(argc, argv2);
71     getopt_cleanup(argc, argv2);
72     
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     }
79
80     return TCL_OK;
81 }
82
83
84
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;
93     
94     argv2 = getopt_init(argc, argv);
95     rrd_dump(argc, argv2);
96     getopt_cleanup(argv, argv2);
97
98     /* NOTE: rrd_dump() writes to stdout. No interaction with TCL. */
99
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     }
106
107     return TCL_OK;
108 }
109
110
111
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;
121     
122     argv2 = getopt_init(argc, argv);
123     t = rrd_last(argc, argv2);
124     getopt_cleanup(argv, argv2);
125
126
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     }
133
134     Tcl_SetIntObj(Tcl_GetObjResult(interp), t);
135
136     return TCL_OK;
137 }
138
139
140
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;
149     
150     argv2 = getopt_init(argc, argv);
151     rrd_update(argc, argv2);
152     getopt_cleanup(argv, argv2);
153
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     }
160
161     return TCL_OK;
162 }
163
164
165
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;
180     
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);
198
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     }
205
206     return TCL_OK;
207 }
208
209
210
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;
223     
224     calcpr = NULL;
225
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;
234             
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);
244
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     }
251
252     return TCL_OK;
253 }
254
255
256
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;
265     
266     argv2 = getopt_init(argc, argv);
267     rrd_tune(argc, argv2);
268     getopt_cleanup(argv, argv2);
269
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     }
276
277     return TCL_OK;
278 }
279
280
281
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;
290     
291     argv2 = getopt_init(argc, argv);
292     rrd_resize(argc, argv2);
293     getopt_cleanup(argv, argv2);
294
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     }
301
302     return TCL_OK;
303 }
304
305
306
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;
315     
316     argv2 = getopt_init(argc, argv);
317     rrd_restore(argc, argv2);
318     getopt_cleanup(argv, argv2);
319
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     }
326
327     return TCL_OK;
328 }
329
330
331
332 /*
333  * The following structure defines the commands in the Rrd extension.
334  */
335
336 typedef struct {
337     char *name;                 /* Name of the command. */
338     Tcl_CmdProc *proc;          /* Procedure for command. */
339 } CmdInfo;
340
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 };
353
354
355
356 int
357 Tclrrd_Init(interp, safe)
358     Tcl_Interp *interp;
359     int safe;
360
361     CmdInfo *cmdInfoPtr;
362     Tcl_CmdInfo info;
363
364     if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
365         return TCL_ERROR;
366     }
367
368     Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY);
369
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     }
384
385     if (Tcl_PkgProvide(interp, "Rrd", VERSION) != TCL_OK) {
386         return TCL_ERROR;
387     }
388
389     return TCL_OK;
390 }