Initial revision
[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     Tcl_Obj *listPtr;
221     char **argv2;
222     
223     calcpr = NULL;
224
225     argv2 = getopt_init(argc, argv);
226     if (rrd_graph(argc, argv2, &calcpr, &xsize, &ysize) != -1 ) {
227         listPtr = Tcl_GetObjResult(interp);
228         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(xsize));
229         Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(ysize));
230         if (calcpr) {
231 #if 0
232             int i;
233             
234             for(i = 0; calcpr[i]; i++){
235                 printf("%s\n", calcpr[i]);
236                 free(calcpr[i]);
237             } 
238 #endif
239             free(calcpr);
240         }
241     }
242     getopt_cleanup(argv, argv2);
243
244     if (rrd_test_error()) {
245         Tcl_AppendResult(interp, "RRD Error: ",
246                          rrd_get_error(), (char *) NULL);
247         rrd_clear_error();
248         return TCL_ERROR;
249     }
250
251     return TCL_OK;
252 }
253
254
255
256 static int
257 Rrd_Tune(clientData, interp, argc, argv)
258     ClientData clientData;
259     Tcl_Interp *interp;
260     int argc;
261     char *argv[];
262 {
263     char **argv2;
264     
265     argv2 = getopt_init(argc, argv);
266     rrd_tune(argc, argv2);
267     getopt_cleanup(argv, argv2);
268
269     if (rrd_test_error()) {
270         Tcl_AppendResult(interp, "RRD Error: ",
271                          rrd_get_error(), (char *) NULL);
272         rrd_clear_error();
273         return TCL_ERROR;
274     }
275
276     return TCL_OK;
277 }
278
279
280
281 static int
282 Rrd_Resize(clientData, interp, argc, argv)
283     ClientData clientData;
284     Tcl_Interp *interp;
285     int argc;
286     char *argv[];
287 {
288     char **argv2;
289     
290     argv2 = getopt_init(argc, argv);
291     rrd_resize(argc, argv2);
292     getopt_cleanup(argv, argv2);
293
294     if (rrd_test_error()) {
295         Tcl_AppendResult(interp, "RRD Error: ",
296                          rrd_get_error(), (char *) NULL);
297         rrd_clear_error();
298         return TCL_ERROR;
299     }
300
301     return TCL_OK;
302 }
303
304
305
306 static int
307 Rrd_Restore(clientData, interp, argc, argv)
308     ClientData clientData;
309     Tcl_Interp *interp;
310     int argc;
311     char *argv[];
312 {
313     char **argv2;
314     
315     argv2 = getopt_init(argc, argv);
316     rrd_restore(argc, argv2);
317     getopt_cleanup(argv, argv2);
318
319     if (rrd_test_error()) {
320         Tcl_AppendResult(interp, "RRD Error: ",
321                          rrd_get_error(), (char *) NULL);
322         rrd_clear_error();
323         return TCL_ERROR;
324     }
325
326     return TCL_OK;
327 }
328
329
330
331 /*
332  * The following structure defines the commands in the Rrd extension.
333  */
334
335 typedef struct {
336     char *name;                 /* Name of the command. */
337     Tcl_CmdProc *proc;          /* Procedure for command. */
338 } CmdInfo;
339
340 static CmdInfo rrdCmds[] = {
341     { "Rrd::create",    Rrd_Create              },
342     { "Rrd::dump",      Rrd_Dump                },
343     { "Rrd::last",      Rrd_Last                },
344     { "Rrd::update",    Rrd_Update              },
345     { "Rrd::fetch",     Rrd_Fetch               },
346     { "Rrd::graph",     Rrd_Graph               },
347     { "Rrd::tune",      Rrd_Tune                },
348     { "Rrd::resize",    Rrd_Resize              },
349     { "Rrd::restore",   Rrd_Restore             },
350     { (char *) NULL,    (Tcl_CmdProc *) NULL    }
351 };
352
353
354
355 int
356 Tclrrd_Init(interp, safe)
357     Tcl_Interp *interp;
358     int safe;
359
360     CmdInfo *cmdInfoPtr;
361     Tcl_CmdInfo info;
362
363     if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 1) == NULL) {
364         return TCL_ERROR;
365     }
366
367     Tcl_SetVar2(interp, "rrd", "version", VERSION, TCL_GLOBAL_ONLY);
368
369     for (cmdInfoPtr = rrdCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
370         /*
371          * Check if the command already exists and return an error
372          * to ensure we detect name clashes while loading the Rrd
373          * extension.
374          */
375         if (Tcl_GetCommandInfo(interp, cmdInfoPtr->name, &info)) {
376             Tcl_AppendResult(interp, "command \"", cmdInfoPtr->name,
377                              "\" already exists", (char *) NULL);
378             return TCL_ERROR;
379         }
380         Tcl_CreateCommand(interp, cmdInfoPtr->name, cmdInfoPtr->proc,
381                           (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
382     }
383
384     if (Tcl_PkgProvide(interp, "Rrd", VERSION) != TCL_OK) {
385         return TCL_ERROR;
386     }
387
388     return TCL_OK;
389 }