I finally finished the first version of the patch (attached) -- Fidelis Assis fideli...
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Mon, 22 Sep 2008 06:35:26 +0000 (06:35 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Mon, 22 Sep 2008 06:35:26 +0000 (06:35 +0000)
(this does not seem to quite work yet at least not in my hardy setup)

git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1517 a5681a0c-68f1-0310-ab6d-d61299d08faa

MakeMakefile
bindings/Makefile.am
bindings/lua/Makefile.lua [new file with mode: 0644]
bindings/lua/README [new file with mode: 0644]
bindings/lua/rrdlua.c [new file with mode: 0644]
bindings/lua/test.lua [new file with mode: 0644]
configure.ac
doc/Makefile.am
doc/rrdlua.pod [new file with mode: 0644]

index aca14cc..f945d3b 100755 (executable)
@@ -3,8 +3,8 @@
 # Run this script after the first cvs checkout to build
 # makefiles and friends
 
-PATH="/usr/sepp/bin:$PATH"
-export PATH
+#PATH="/usr/sepp/bin:$PATH"
+#export PATH
 
 vcheck (){
   perl <<PERL
index cd5cd21..61cadf3 100644 (file)
@@ -1,4 +1,4 @@
-.PHONY: python ruby
+.PHONY: python ruby lua
 
 if BUILD_TCL
 SUB_tcl = tcl
@@ -10,28 +10,33 @@ SUBDIRS = $(SUB_tcl)
 EXTRA_DIST = perl-piped/MANIFEST perl-piped/README perl-piped/Makefile.PL perl-piped/RRDp.pm perl-piped/t/base.t \
             perl-shared/ntmake.pl perl-shared/MANIFEST perl-shared/README perl-shared/Makefile.PL perl-shared/RRDs.pm  perl-shared/RRDs.xs perl-shared/t/base.t \
             ruby/CHANGES     ruby/README      ruby/extconf.rb  ruby/main.c      ruby/test.rb \
-             python/ACKNOWLEDGEMENT python/AUTHORS python/COPYING python/README python/rrdtoolmodule.c python/setup.py
+             python/ACKNOWLEDGEMENT python/AUTHORS python/COPYING python/README python/rrdtoolmodule.c python/setup.py \
+            lua/README lua/test.lua lua/rrdlua.c lua/Makefile.lua lua/rrdlua.pod 
 
 
 # add the following to the all target
-all-local:  @COMP_PERL@ @COMP_RUBY@ @COMP_PYTHON@
+all-local:  @COMP_PERL@ @COMP_RUBY@ @COMP_PYTHON@ @COMP_LUA@
 
 install-data-local:
        test -f perl-piped/Makefile && cd perl-piped && $(MAKE) install || true
        test -f perl-shared/Makefile && cd perl-shared && $(MAKE) install || true
        test -f ruby/Makefile && cd ruby && $(MAKE) EPREFIX=$(DESTDIR)$(exec_prefix) $(RUBY_MAKE_OPTIONS) install || true
        test -d python/build && cd python && env BUILDLIBDIR=../../src/.libs $(PYTHON) setup.py install --skip-build --prefix=$(DESTDIR)$(prefix) --exec-prefix=$(DESTDIR)$(exec_prefix) || true
+       test -f lua/Makefile && cd lua && $(MAKE) install || true
 
-# rules for buildung the ruby module
+# rules for building the ruby module
 # RUBYARCHDIR= is to work around in a makefile quirk not sure 
 # it is is the right thing todo, but it makes rrdtool build on freebsd as well
 ruby: 
        cd ruby && $(RUBY) extconf.rb && $(MAKE) EPREFIX=$(exec_prefix) $(RUBY_MAKE_OPTIONS) RUBYARCHDIR=
 
-# rules for buildung the pyton module
+# rules for building the pyton module
 python:
        cd python && env BUILDLIBDIR=../../src/.libs $(PYTHON) setup.py build_ext --rpath=$(libdir) && env LIBDIR=../../src/.libs $(PYTHON) setup.py build
 
+lua:
+       cd lua && $(LUA) Makefile.lua "PREFIX=$(prefix) POD2MAN=$(POD2MAN) LUABIN=$(LUA) $(LUA_MAKE_OPTIONS)" > Makefile && $(MAKE)
+
 # rules for building the perl module
 perl_piped: perl-piped/Makefile
        cd perl-piped && $(MAKE)
@@ -52,5 +57,6 @@ clean-local:
        test -f perl-shared/Makefile && cd perl-shared && $(MAKE) clean || true
        test -f perl-shared/Makefile && rm -f perl-shared/Makefile || true 
        test -f ruby/Makefile && cd ruby && $(MAKE) clean && rm Makefile || true 
+       test -f lua/Makefile && cd lua && $(MAKE) clean && rm Makefile || true 
        test -d python/build && cd python &&  rm -rf build || true
 ##END##
diff --git a/bindings/lua/Makefile.lua b/bindings/lua/Makefile.lua
new file mode 100644 (file)
index 0000000..08be1cc
--- /dev/null
@@ -0,0 +1,120 @@
+-- min version
+local min_major, min_minor = 5, 1
+local major, minor = string.match(_VERSION, 'Lua (%d+)\.(%d*)')
+
+if (tonumber(major)  < min_major or
+    tonumber(major) == min_major and tonumber(minor) < min_minor) then
+  error(string.format(
+       '\n\n*** Lua rrdtool module requires Lua %d.%d or greater. ***\n',
+       min_major, min_minor))
+  os.exit(1)
+end
+local lua_version = major .. '.' .. minor
+
+local options = arg[1]
+if options then
+  io.write(string.gsub(options, ' (%S-=)', '\n%1'), '\n\n')
+end
+
+io.stdout:write([[
+T= rrd
+# Version
+LIB_VERSION=0.0.8
+LUA_VERSION=]],major, '.',minor,[[
+
+
+# set lua include, lib and C installation dirs
+PKG_CONFIG=$(firstword $(shell which pkg-config))
+ifeq (pkg-config,$(findstring pkg-config,$(PKG_CONFIG)))
+  LUA_LIBDIR=$(shell pkg-config --variable=INSTALL_CMOD lua$(LUA_VERSION))
+  ifeq (,$(LUA_LIBDIR))
+    $(warning *** couldn't find lua$(LUA_VERSION).pc)
+  else
+    LUA_CFLAGS=$(shell pkg-config --cflags lua$(LUA_VERSION) 2>/dev/null)
+    LUA_LFLAGS=$(shell pkg-config --libs lua$(LUA_VERSION) 2>/dev/null)
+  endif
+else
+  $(warning couldn't find pkg-config)
+endif
+
+ifeq (,$(LUA_LIBDIR))
+    $(warning *** setting Lua dirs to defaults in src package)
+    LUA_CFLAGS=-I/usr/local/include -I/usr/local/include/lua
+    LUA_LFLAGS=-L/usr/local/lib/lua/$(LUA_VERSION) -llua
+    LUA_LIBDIR=/usr/local/lib/lua/$(LUA_VERSION)
+endif
+
+]])
+
+-- overwrite global LUA_LIBDIR if default lib is set
+if lib then
+  io.stdout:write([[
+# override LUA_LIBDIR for site install
+LUA_LIBDIR=]],lib,[[/$(LUA_VERSION)
+]])
+end
+
+io.stdout:write([[
+
+# OS dependent
+LIB_EXT= .so
+
+# if this "autoconf" doesn't work for you, set LIB_OPTION for shared
+# object manually.
+LD=$(shell ld -V -o /dev/null 2>&1)
+ifneq (,$(findstring Solaris,$(LD)))
+ # Solaris - tested with 2.6, gcc 2.95.3 20010315 and Solaris ld
+ LIB_OPTION= -G -dy
+else
+ ifneq (,$(findstring GNU,$(LD)))
+  # GNU ld
+  LIB_OPTION= -shared -dy
+ else
+  $(error couldn't identify your ld. Please set the shared option manually)
+ endif
+endif
+
+RRD_CFLAGS=-I../../src/
+RRD_LIB_DIR=-L../../src/.libs -lrrd
+
+# Choose the PIC option
+# safest, works on most systems
+PIC=-fPIC
+# probably faster, but may not work on your system
+#PIC=-fpic
+
+# Compilation directives
+OPTIONS= -O3 -Wall ${PIC} -fomit-frame-pointer -pedantic-errors -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings
+LIBS= $(RRD_LIB_DIR) $(LUA_LFLAGS) -lm
+CFLAGS= $(OPTIONS) $(LUA_CFLAGS) $(RRD_CFLAGS) -DLIB_VERSION=\"$(LIB_VERSION)\"
+#CC= gcc
+
+LIBNAME= $T-$(LIB_VERSION)$(LIB_EXT)
+
+SRCS= rrdlua.c
+OBJS= rrdlua.o
+
+all: $(LIBNAME)
+
+lib: $(LIBNAME)
+
+*.o:   *.c
+
+$(LIBNAME): $(OBJS)
+       $(CC) $(CFLAGS) $(LIB_OPTION) $(OBJS) $(LIBS) -o $(LIBNAME)
+
+install: $(LIBNAME)
+       mkdir -p $(LUA_LIBDIR)
+       cp $(LIBNAME) $(LUA_LIBDIR)
+       strip $(LUA_LIBDIR)/$(LIBNAME)
+       (cd $(LUA_LIBDIR) ; rm -f $T$(LIB_EXT) ; ln -fs $(LIBNAME) $T$(LIB_EXT))
+       $(POD2MAN) --release=$(VERSION) --center=RRDLua --section=3 rrdlua.pod > $(PREFIX)/man/man3/rrdlua.3
+
+test: $(LIBNAME)
+       ln -sf $(LIBNAME) rrd.so
+       lua test.lua
+
+clean:
+       rm -f $L $(LIBNAME) $(OBJS) *.so *.rrd *.xml *.png *~
+]])
+
diff --git a/bindings/lua/README b/bindings/lua/README
new file mode 100644 (file)
index 0000000..f1fe186
--- /dev/null
@@ -0,0 +1,21 @@
+RRDLua is a Lua module for RRD functions.
+
+Compiling:
+
+Just run "configure" from the top RRDTool package dir and then 'make'.
+You should have lua and lua-dev packages installed before executing
+configure.
+
+Testing:
+
+Enter the bindings/lua dir, run 'make test' and use your preferred
+viewer to display the just created graph 'test.png'. If you can read
+"Enjoy Lua RRDtool module!" on the picture, everything went fine.
+
+Installation:
+
+Run 'make install' from the top dir of the RRDtool package. The Lua
+module will be installed in the same RRDtool installation dir,
+under the subdir lib/lua/<lua_version>.
+
+
diff --git a/bindings/lua/rrdlua.c b/bindings/lua/rrdlua.c
new file mode 100644 (file)
index 0000000..a786077
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Lua bindings for RRDTool
+ *
+ * This software is licensed to the public under the Free Software
+ * Foundation's GNU GPL, version 2 or later. You may obtain a copy
+ * of the GPL by visiting the Free Software Foundations web site at
+ * www.fsf.org, and a copy is included in this distribution.
+ *
+ * Copyright 2008 Fidelis Assis, all rights reserved.
+ *
+ */
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include <dirent.h>
+#include <inttypes.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "../../src/rrd_tool.h"
+
+extern void rrd_freemem(void *mem);
+
+extern int luaopen_rrd (lua_State * L);
+typedef int (*RRD_FUNCTION)(int, char **);
+typedef rrd_info_t *(RRD_FUNCTION_V)(int, char **);
+
+/**********************************************************/
+
+static void reset_rrd_state(void)
+{
+    optind = 0;
+    opterr = 0;
+    rrd_clear_error();
+}
+
+static char **make_argv(const char *cmd, lua_State * L)
+{
+  char **argv;
+  int i;
+  int argc = lua_gettop(L) + 1;
+
+  if (!(argv = calloc(argc, sizeof (char *)))) 
+    /* raise an error and never return */
+    luaL_error(L, "Can't allocate memory for arguments array", cmd);
+
+  /* fprintf(stderr, "Args:\n"); */
+  argv[0] = (char *) cmd; /* Dummy arg. Cast to (char *) because rrd */
+                          /* functions don't expect (const * char)   */
+  /* fprintf(stderr, "%s\n", argv[0]); */
+  for (i=1; i<argc; i++) {
+    /* accepts string or number */
+    if (lua_isstring(L, i) || lua_isnumber(L, i)) {
+      if (!(argv[i] = strdup(lua_tostring (L, i)))) {
+        /* raise an error and never return */
+        luaL_error(L, "%s - error duplicating string area for arg #%d",
+                   cmd, i);
+      }
+    } else {
+      /* raise an error and never return */
+      luaL_error(L, "Invalid arg #%d to %s: args must be strings or numbers",
+                 i, cmd);
+    }
+    /* fprintf(stderr, "%s\n", argv[i]); */
+  }
+  return argv;
+}
+
+static int
+rrd_common_call (lua_State *L, const char *cmd, RRD_FUNCTION rrd_function)
+{
+  char **argv;
+  int argc = lua_gettop(L) + 1;
+
+  argv = make_argv(cmd, L);
+  reset_rrd_state();
+  rrd_function(argc, argv);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+  return 0;
+}
+
+#if defined(DINF)
+static int
+lua_rrd_infocall(lua_State *L, const char *cmd, RRD_FUNCTION_V rrd_function)
+{
+  char **argv;
+  rrd_info_t *p, *data;
+  int argc = lua_gettop(L) + 1;
+
+  argv = make_argv(cmd, L);
+  reset_rrd_state();
+  data = rrd_function(argc, argv);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+
+  lua_newtable(L);
+  p = data;
+  while (data) {
+    lua_pushstring(L, data->key);
+    switch (data->type) {
+      case RD_I_CNT:
+        if (isnan(data->value.u_val)) {
+          lua_pushnil(L); 
+        } else {
+          lua_pushnumber(L, (lua_Number) data->value.u_val);
+        }
+        lua_rawset(L, -3);
+        break;
+      case RD_I_VAL:
+        lua_pushnumber(L, (lua_Number) data->value.u_val);
+        lua_rawset(L, -3);
+        break;
+      case RD_I_STR:
+        lua_pushstring(L, data->value.u_str);
+        lua_rawset(L, -3);
+        break;
+      case RD_I_BLO:
+        lua_pushlstring(L, (const char *) data->value.u_blo.ptr,
+                        data->value.u_blo.size);
+        lua_rawset(L, -3);
+        break;
+      default:
+        rrd_info_free(p); 
+        return luaL_error(L, "Wrong data type to info call");
+        break;
+    }
+    data = data->next;
+  }
+  rrd_info_free(p); 
+  return 1;
+}
+#endif
+
+/**********************************************************/
+
+static int
+lua_rrd_create (lua_State * L)
+{
+  rrd_common_call(L, "create", rrd_create);
+  return 0;
+}
+
+static int
+lua_rrd_dump (lua_State * L)
+{
+  rrd_common_call(L, "dump", rrd_dump);
+  return 0;
+}
+
+static int
+lua_rrd_resize (lua_State * L)
+{
+  rrd_common_call(L, "resize", rrd_resize);
+  return 0;
+}
+
+static int
+lua_rrd_restore (lua_State * L)
+{
+  rrd_common_call(L, "restore", rrd_restore);
+  return 0;
+}
+
+static int
+lua_rrd_tune (lua_State * L)
+{
+  rrd_common_call(L, "tune", rrd_tune);
+  return 0;
+}
+
+static int
+lua_rrd_update (lua_State * L)
+{
+  rrd_common_call(L, "update", rrd_update);
+  return 0;
+}
+
+static int
+lua_rrd_fetch (lua_State * L)
+{
+  int argc = lua_gettop(L) + 1;
+  char **argv = make_argv("fetch", L);
+  unsigned long i, j, step, ds_cnt;
+  rrd_value_t *data, *p;
+  char    **names;
+  time_t  t, start, end;
+
+  reset_rrd_state();
+  rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &names, &data);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+
+  lua_pushnumber(L, (lua_Number) start);
+  lua_pushnumber(L, (lua_Number) step);
+  /* fprintf(stderr, "%lu, %lu, %lu, %lu\n", start, end, step, num_points); */
+
+  /* create the ds names array */
+  lua_newtable(L);
+  for (i=0; i<ds_cnt; i++) {
+    lua_pushstring(L, names[i]);
+    lua_rawseti(L, -2, i+1);
+    rrd_freemem(names[i]);
+  }
+  rrd_freemem(names);
+
+  /* create the data points array */
+  lua_newtable(L);
+  p = data;
+  for (t=start, i=0; t<end; t+=step, i++) {
+    lua_newtable(L);
+    for (j=0; j<ds_cnt; j++) {
+      /*fprintf(stderr, "Point #%lu\n", j+1); */
+      lua_pushnumber(L, (lua_Number) *p++);
+      lua_rawseti(L, -2, j+1);
+    }
+    lua_rawseti(L, -2, i+1);
+  }
+  rrd_freemem(data);
+
+  /* return the end as the last value */
+  lua_pushnumber(L, (lua_Number) end);
+
+  return 5;
+}
+
+static int
+lua_rrd_first (lua_State * L)
+{
+  time_t first;
+  int argc = lua_gettop(L) + 1;
+  char **argv = make_argv("first", L);
+  reset_rrd_state();
+  first = rrd_first(argc, argv);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+  lua_pushnumber(L, (lua_Number) first);
+  return 1;
+}
+
+static int
+lua_rrd_last (lua_State * L)
+{
+  time_t last;
+  int argc = lua_gettop(L) + 1;
+  char **argv = make_argv("last", L);
+  reset_rrd_state();
+  last = rrd_last(argc, argv);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+  lua_pushnumber(L, (lua_Number) last);
+  return 1;
+}
+
+static int
+lua_rrd_graph (lua_State * L)
+{
+  int argc = lua_gettop(L) + 1;
+  char **argv = make_argv("last", L);
+  char **calcpr;
+  int i, xsize, ysize;
+  double ymin, ymax;
+
+  reset_rrd_state();
+  rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
+  free(argv);
+  if (rrd_test_error()) luaL_error(L, rrd_get_error());
+  lua_pushnumber(L, (lua_Number) xsize);
+  lua_pushnumber(L, (lua_Number) ysize);
+  lua_newtable(L);
+  for (i = 0; calcpr && calcpr[i]; i++) {
+      lua_pushstring(L, calcpr[i]);
+      lua_rawseti(L, -2, i+1);
+      rrd_freemem(calcpr[i]);
+  }
+  rrd_freemem(calcpr);
+  return 3;
+}
+
+#if defined(DINF)
+static int
+lua_rrd_info (lua_State * L)
+{
+  return lua_rrd_infocall(L, "info", rrd_info);
+}
+
+static int
+lua_rrd_graphv (lua_State * L)
+{
+  return lua_rrd_infocall(L, "graphv", rrd_graph_v);
+}
+
+static int
+lua_rrd_updatev (lua_State * L)
+{
+  return lua_rrd_infocall(L, "updatev", rrd_update_v);
+}
+#endif
+
+/**********************************************************/
+
+/*
+** Assumes the table is on top of the stack.
+*/
+static void
+set_info (lua_State * L)
+{
+  lua_pushliteral (L, "_COPYRIGHT");
+  lua_pushliteral (L, "Copyright (C) 2008 Fidelis Assis");
+  lua_settable (L, -3);
+  lua_pushliteral (L, "_DESCRIPTION");
+  lua_pushliteral (L, "RRD-lua is a Lua binding for RRDTool.");
+  lua_settable (L, -3);
+  lua_pushliteral (L, "_NAME");
+  lua_pushliteral (L, "RRD-Lua");
+  lua_settable (L, -3);
+  lua_pushliteral (L, "_VERSION");
+  lua_pushliteral (L, LIB_VERSION);
+  lua_settable (L, -3);
+}
+
+/**********************************************************/
+
+static const struct luaL_reg rrd[] = {
+  {"create", lua_rrd_create},
+  {"dump", lua_rrd_dump},
+  {"fetch", lua_rrd_fetch},
+  {"first", lua_rrd_first},
+  {"graph", lua_rrd_graph},
+  {"last", lua_rrd_last},
+  {"resize", lua_rrd_resize},
+  {"restore", lua_rrd_restore},
+  {"tune", lua_rrd_tune},
+  {"update", lua_rrd_update},
+#if defined(DINF)
+  {"info", lua_rrd_info},
+  {"updatev", lua_rrd_updatev},
+  {"graphv", lua_rrd_graphv},
+#endif
+  {NULL, NULL}
+};
+
+
+/*
+** Open RRD library
+*/
+int
+luaopen_rrd (lua_State * L)
+{
+  luaL_register (L, "rrd", rrd);
+  set_info (L);
+  return 1;
+}
diff --git a/bindings/lua/test.lua b/bindings/lua/test.lua
new file mode 100644 (file)
index 0000000..541330c
--- /dev/null
@@ -0,0 +1,98 @@
+-- Test script adapted from the one in the Ruby binding.
+
+local rrd = require "rrd"
+
+local name = "test.rrd"
+local start = 300 * math.floor(os.time() / 300)
+
+io.write('\n-- Creating ', name, '\n')
+rrd.create(
+    name,
+    "--start", start-1,
+    "--step", "300",
+    "DS:a:GAUGE:600:U:U",
+    "DS:b:GAUGE:600:U:U",
+    "RRA:AVERAGE:0.5:1:300")
+
+local num_points = 0
+for t=start, start+300*300, 300 do
+  local s = string.format('%d:%d:%f', t,
+                          math.random(100), math.sin(t/800)*50+50)
+  rrd.update(name, s)
+  num_points = num_points + 1
+end
+
+io.write('rrd file created with ', num_points, ' points, from ', start,
+         ' to ', start+300*300, '\n')
+
+io.write('\n-- Testing rrd.info\n')
+local info = rrd.info(name)
+for k,v in pairs(info) do
+  io.write(k, '=', v, '\n')
+end
+io.write('\n')
+
+io.write('-- Testing rrd.fetch\n') 
+io.write("fetching data from ", name, ' - interval: ', start, ' to ',
+         start+300*300, '\n') 
+local fstart, fend, fstep, fnames, fdata =
+  rrd.fetch(name, "--start", start, "--end", start+300*300+10, "AVERAGE")
+io.write('got ', #fdata[1], ' data sources with ', #fdata,
+         ' data points each.\n')
+
+-- uncomment below to print fetched data
+---[[
+io.write('\n-- Printing fetched data\n') 
+io.write('            ')
+for i, n in ipairs(fnames) do
+  io.write(n, '            ')
+end
+io.write('\n')
+for i, v in ipairs(fdata) do
+  local time = fstart + (i-1)*fstep
+  io.write(string.format('%s (%d): ', os.date("%c", time), time))
+  for _, w in ipairs(v) do
+    io.write(string.format('%e ', w))
+  end
+  io.write('\n')
+end
+io.write('\n')
+--]]
+
+io.write('\n-- Testing rrd.graphv - creates test.png and returns values\n') 
+local t = rrd.graphv(
+   "test.png",
+   "--title", "Enjoy Lua RRDTool module!",
+   "--start", start+3600,
+   "--end", "start + 1000 min",
+   "--interlace",
+   "--imgformat", "PNG",
+   "--width=450",
+   "DEF:a=" .. name .. ":a:AVERAGE",
+   "DEF:b=" .. name .. ":b:AVERAGE",
+   "CDEF:line=TIME,2400,%,300,LT,a,UNKN,IF",
+   "AREA:b#00b6e4:beta",
+   "AREA:line#0022e9:alpha",
+   "LINE3:line#ff0000",
+   "VDEF:va=a,AVERAGE",
+   "VDEF:vb=b,AVERAGE",
+   "PRINT:va:%5.2lf",
+   "PRINT:vb:%5.2lf")
+
+io.write('The graph "test.png" was created.\n')
+
+-- uncomment below to print graphv returned data
+--[[
+io.write('\n-- Printing returned values\n') 
+io.write('print[0]: ', t['print[0]'], '\n')
+io.write('print[1]: ', t['print[1]'], '\n')
+for k, v in pairs(t) do
+  if not string.match(k, '^print%[%d+%]') then
+    io.write(k, ': ', v, '\n')
+  end
+end
+io.write('\n')
+--]]
+
+io.write('Use your preferred viewer to display the graph.\n\n')
+
index f12c63e..1e3da86 100644 (file)
@@ -532,10 +532,11 @@ AC_MSG_CHECKING(Perl Modules to build)
 AC_MSG_RESULT(${COMP_PERL:-No Perl Modules will be built})
 
 # Options to pass when configuring perl module
-ppref=$prefix
-test "$ppref" = "NONE" && ppref=$ac_default_prefix
+langpref=$prefix
+test "$langpref" = "$(DESTDIR)NONE" && langpref='$(DESTDIR)'$ac_default_prefix
+test "$langpref" = "NONE" && langpref=$ac_default_prefix
 
-PERL_MAKE_OPTIONS="PREFIX=$ppref LIB=$ppref/lib/perl/$PERL_VERSION"
+PERL_MAKE_OPTIONS="PREFIX=$langpref LIB=$langpref/lib/perl/$PERL_VERSION"
 
 dnl pass additional perl options when generating Makefile from Makefile.PL
 AC_ARG_ENABLE(perl-site-install,
@@ -597,16 +598,13 @@ else
        fi                              
 fi
 
-rpref=$prefix
-test "$rpref" = "NONE" && rpref=$ac_default_prefix
-
 dnl pass additional ruby options when generating Makefile from Makefile.PL
 AC_ARG_ENABLE(ruby-site-install,
 [  --enable-ruby-site-install   by default the rrdtool ruby modules are installed
                          together with rrdtool in $prefix/lib/ruby. You have to
-                          add $prefix/lib/ruby/$ruby_version/$sitearch to you $: variable
+                          add $prefix/lib/ruby/$ruby_version/$sitearch to your $: variable
                           for ruby to find the RRD.so file.],
-[RUBY_MAKE_OPTIONS=],[RUBY_MAKE_OPTIONS="sitedir="'$(DESTDIR)'"$rpref/lib/ruby"])
+[RUBY_MAKE_OPTIONS=],[RUBY_MAKE_OPTIONS="sitedir=$langpref/lib/ruby"])
 
     
 AC_ARG_WITH(ruby-options,
@@ -620,6 +618,49 @@ AC_SUBST(RUBY_MAKE_OPTIONS)
 AC_SUBST(RUBY)
 AC_SUBST(COMP_RUBY)
 
+dnl Check for Lua.
+AC_PATH_PROG(LUA, lua, no)
+
+AC_ARG_ENABLE(lua,[  --disable-lua          do not build the lua modules],
+[],[enable_lua=yes])
+
+AC_MSG_CHECKING(if lua modules can be built)
+
+COMP_LUA=
+if test "x$LUA" = "xno" -o  x$enable_lua = xno; then
+  AC_MSG_RESULT(No .. Lua not found or disabled)
+else
+  for dir in /usr/include/lua /usr/include/lua5.1 /usr/local/include/lua5.1 /usr/include/lua5.2 /usr/local/include/lua5.2 ; do
+    if test -f "$dir/lualib.h" ; then
+      enable_lua=yes
+      COMP_LUA="lua"
+      break
+    fi
+  done
+
+  if test "$COMP_LUA" = "lua" ; then
+    AC_MSG_RESULT(YES)
+  else
+    AC_MSG_RESULT(Lua found but lualib.h is missing! Install the -dev package)
+  fi
+fi
+
+dnl pass additional lua options
+# if lua-site-install is set, don't set 'LIB' and let Lua setup decide
+# the best place.
+AC_ARG_ENABLE(lua-site-install,
+[  --enable-lua-site-install   by default the rrdtool lua modules are installed
+                          together with rrdtool in $prefix/lib/lua. You have to
+                          add $prefix/lib/lua/$lua_version/?.so to package.cpath
+                          for lua to find the rrd.so file.]. When you set this
+                         option the Lua module will get installed wherever
+                          your Lua setup thinks it is best.],
+[LUA_MAKE_OPTIONS=],[LUA_MAKE_OPTIONS="LIB=$langpref/lib/lua"])
+
+AC_SUBST(LUA_MAKE_OPTIONS)
+AC_SUBST(LUA)
+AC_SUBST(COMP_LUA)
+
 
 enable_tcl_site=no
 
@@ -748,6 +789,9 @@ echo "          Perl Options: $PERL_MAKE_OPTIONS"
 echo "          Ruby Modules: $COMP_RUBY"
 echo "           Ruby Binary: $RUBY"
 echo "          Ruby Options: $RUBY_MAKE_OPTIONS"
+echo "           Lua Modules: $COMP_LUA"
+echo "            Lua Binary: $LUA"
+echo "           Lua Options: $LUA_MAKE_OPTIONS"
 echo "    Build Tcl Bindings: $enable_tcl"
 echo " Build Python Bindings: $enable_python"
 echo "          Build rrdcgi: $enable_rrdcgi"
index 8e52084..2273ab6 100644 (file)
@@ -13,7 +13,7 @@ POD = bin_dec_hex.pod        rrddump.pod            rrdgraph_examples.pod  rrdre
       rpntutorial.pod        rrdfirst.pod           rrdgraph_rpn.pod       rrdtool.pod            rrdcached.pod  \
       rrd-beginners.pod      rrdinfo.pod            rrdtune.pod            rrdbuild.pod           rrdflush.pod   \
       rrdcgi.pod             rrdgraph.pod           rrdlast.pod            rrdlastupdate.pod                     \
-      rrdcreate.pod          rrdgraph_data.pod      rrdresize.pod          rrdtutorial.pod                       
+      rrdcreate.pod          rrdgraph_data.pod      rrdresize.pod          rrdtutorial.pod        rrdlua.pod
 
 
 PMP = RRDs.pod RRDp.pod
diff --git a/doc/rrdlua.pod b/doc/rrdlua.pod
new file mode 100644 (file)
index 0000000..a6240f2
--- /dev/null
@@ -0,0 +1,137 @@
+=head1 NAME
+
+RRDLua -  Lua binding for RRDTool
+
+=head1 SYNOPSIS
+
+  require 'rrd'
+  rrd.create(...)
+  rrd.dump(...)
+  rrd.fetch(...)
+  rrd.first(...)
+  rrd.graph(...)
+  rrd.graphv(...)
+  rrd.info(...)
+  rrd.last(...)
+  rrd.resize(...)
+  rrd.restore(...)
+  rrd.tune(...)
+  rrd.update(...)
+  rrd.updatev(...)
+
+=head1 DESCRIPTION
+
+=head2 Calling Sequence
+
+This module accesses RRDtool functionality directly from within Lua.
+The arguments to the functions listed in the SYNOPSIS are explained in
+the regular RRDtool documentation. The command-line call
+
+  rrdtool update mydemo.rrd --template in:out N:12:13
+
+gets turned into
+
+  rrd.update ("mydemo.rrd", "--template", "in:out", "N:12:13")
+
+Note that
+
+  --template=in:out is also valid.
+
+=head2 Error Handling
+
+The Lua RRDTool module functions will abort your program with a stack
+traceback when they can not make sense out of the arguments you fed them.
+
+  Ex:
+
+  -- If the Lua RRDTool module was installed together with RRDTool,
+  -- in $prefix/lib/lua/$lua_version, package.cpath must be set like
+  -- in the example below, so that 'require' can find the module:
+
+  package.cpath = '/usr/local/rrdtool-1.3.3/lib/lua/5.1/?.so;' ..
+                  package.cpath
+  local rrd = require 'rrd'
+  rrd.update ("mydemo.rrd","N:12:13")
+
+  $ lua t.lua
+
+  lua: t.lua:8: opening 'mydemo.rrd': No such file or directory
+  stack traceback:
+          [C]: in function 'update'
+          t.lua:8: in main chunk
+          [C]: ?
+
+You may capture and handle the errors yourself, instead of just letting
+the program abort, by calling the module functions through Lua protected
+calls - 'pcall' or 'xpcall'.
+
+=head2 Return Values
+
+The functions rrd.first, rrd.last, rrd.graph, rrd.info and rrd.fetch
+return their findings.
+
+B<rrd.first> returns a single INTEGER representing the timestamp of the
+first data sample in an RRA within an RRD file. Example returning the
+first timestamp of the third RRA (index 2):
+
+  local firstdate = rrd.first('example.rrd', '--rraindex', 2)
+
+B<rrd.last> returns a single INTEGER representing the last update time.
+
+  local lastupdate = rrd.last('example.rrd')
+
+B<rrd.graph> returns the x-size and y-size of the created image and a table
+with the results of the PRINT arguments.
+
+  local xsize, ysize, averages = rrd.graph ...
+  print(string.format("Image size: %dx%d", xsize, ysize)
+  print("Averages: ", table.concat(averages, ', '))
+
+B<rrd.info> returns a table where the keys and the values represent property
+names and property values of the RRD.
+
+  local info = rrd.info("test.rrd")
+  for key, value in pairs(info) do
+    print(key, ' = ', value)
+  end
+
+B<rrd.graphv> takes the same parameters as rrd.graph but it returns a table
+only. The table returned contains meta information about the graph, like
+its size as well as the position of the graph area on the image. When
+called with and empty filename, the contents of the graph will be returned
+in the table as well (key 'image').
+
+B<rrd.updatev> also returns a table. The keys of the table are strings
+formed by the concatenation of timestamp, RRA index and data source name
+for each consolidated data point (CDP) written to disk as a result of the
+current update call. The key values are CDP values.
+
+B<rrd.fetch> is the most complex of the pack regarding return values. It
+returns 5 values: the initial timestamp, the step, two parallel arrays
+containing the data source names and their data points respectively, and
+the final timestamp.
+
+  package.cpath = '/usr/local/rrdtool-1.3.3/lib/lua/5.1/?.so;' ..
+                   package.cpath
+  local rrd = require "rrd"
+  local first, last = rrd.first("test.rrd"), rrd.last("test.rrd")
+  local start, step, names, data =
+    rrd.fetch("test.rrd", "--start", first, "--end", last, "AVERAGE")
+  io.write(string.format("Start:       %s (%d)\n",
+                         os.date("%c", start),start))
+  io.write("Step size:   ", step, " seconds\n")
+  io.write("DS names:    ", table.concat(names, ', '), "\n")
+  io.write("Data points: ", #data[1], "\n")
+  io.write("Data:\n")
+  for i,dp in ipairs(data) do
+    io.write(os.date("%t", start), " (", start, "): ")
+    start = start + step
+    for j,v in ipairs(dp) do
+      io.write(v, " ")
+    end
+  io.write("\n")
+  end
+
+=head1 AUTHOR
+
+Fidelis Assis E<lt>fidelis@pobox.comE<gt>